生活随笔
收集整理的這篇文章主要介紹了
iOS AutoLayout
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
iOS AutoLayout
- Autolayout是一種全新的布局技術,專門用來布局UI界面的,用來取代Frame布局在遇見屏幕尺寸多重多樣的問題。Autolayout自iOS 6開始引入,但是由于Xcode 4的不給力,當時并沒有得到大規模推廣。在iOS 7(Xcode5)開始,Autolayout的開發效率得到很大的提升,蘋果官方也推薦開發者盡量使用Autolayout來布局UI界面,減少純代碼的方式。在iOS6之前是用Autoresize布局.
- Autolayout的好處是能夠很方便的適配各種尺寸的屏幕,并且當很好的適配屏幕的橫向和豎向,不會造成使用在有些手機上顯示不全,或者橫豎屏后布局錯位的問題.
- Autolayout父視圖去添加對子視圖的約束,Autoresize是子視圖添加都父視圖的相對位置和大小.
AutoLayout的使用
- AutoLayout常見的使用方式有兩種:
1.IB方式即StoryBoard,Xib;
2.純代碼方式即VFL,NSLayoutConstraint,Masonry,SnapKit.
1.IB方式實現自動布局
-
在xib或者stroyBoard中添加約束的核心思想是一定要確定視圖的frame,不管是設置(Leading,Top,Width,Height),還是設置距離上下左右的間距都是為了確定視圖的farme,根據需求做不同的設置.如果是設置上下左右的間距固定,則視圖的尺寸會不同尺寸的手機顯示的大小不同,如果設置的是Width,Height以及Leading(或者Trailing),Top(或者Bottom),則實體的長寬固定,而沒有添加約束的兩條邊的邊距根據手機的尺寸不同而不同.總至要至少要添加四條約束.
-
但是有些控件添加兩條約束Leading(或者Trailing),Top(或者Bottom)也是可以的,如UILabel,UIimageView,UIButton,如果不設置寬高這些控件會根據內容自動調整大小.IB自動布局大家都比較熟悉,這里就不再詳述.
2.VFL/NSLayoutConstrais方式實現自動布局
- VFL(Virsual Format Language)是一種虛擬的格式化語言,主要用來創建AutoLayout的約束字符串。
- VFL官網介紹
- VFL基本語法介紹:例如: "V:[view1]-0-[view2(==100@1000)]-<=0-|"
功能表達式
| 垂直方向 | V: |
| 水平方向 | H: |
| Views | [view1],[View2] |
| SuperView | | |
| 關系(不寫默認==) | >=,==,<= |
| 空間,間隙(不寫默認值8) | - |
| 優先級 | @value |
- 示例:添加上中下三個視圖,上中視圖等高,下視圖距中間視圖底部的間隙8,并且占滿屏幕剩余部分.
let topView
= UIView()topView
.backgroundColor
= UIColor.redtopView
.translatesAutoresizingMaskIntoConstraints
= falselet middleView
= UIView()middleView
.backgroundColor
= UIColor.greenmiddleView
.translatesAutoresizingMaskIntoConstraints
= falselet bottomView
= UIView()bottomView
.backgroundColor
= UIColor.bluebottomView
.translatesAutoresizingMaskIntoConstraints
= falseview
.addSubview(topView
)view
.addSubview(middleView
)view
.addSubview(bottomView
)let topViewHorizontalContriants
= NSLayoutConstraint.constraints(withVisualFormat
: "H:|-0-[topView]-==0-|", options
:[], metrics
: nil, views
: ["topView":topView
])view
.addConstraints(topViewHorizontalContriants
)let topViewVContriants
= NSLayoutConstraint.constraints(withVisualFormat
: "V:|-64-[topView(==100@1000)]", options
: [], metrics
: nil, views
: ["topView":topView
])view
.addConstraints(topViewVContriants
)let middleTopC
= NSLayoutConstraint.init(item
: middleView
, attribute
: NSLayoutConstraint.Attribute.top
, relatedBy
: NSLayoutConstraint.Relation.equal, toItem
: topView
, attribute
: NSLayoutConstraint.Attribute.bottom
, multiplier
: 1.0, constant
: 0)view
.addConstraint(middleTopC
)let middleleftC
= NSLayoutConstraint.init(item
: middleView
, attribute
: NSLayoutConstraint.Attribute.left, relatedBy
: NSLayoutConstraint.Relation.equal, toItem
: topView
, attribute
: NSLayoutConstraint.Attribute.left, multiplier
: 1.0, constant
: 0)view
.addConstraint(middleleftC
)let middleWidthC
= NSLayoutConstraint.init(item
: middleView
, attribute
: NSLayoutConstraint.Attribute.width
, relatedBy
: NSLayoutConstraint.Relation.equal, toItem
: topView
, attribute
: NSLayoutConstraint.Attribute.width
, multiplier
: 1.0, constant
: 0)view
.addConstraint(middleWidthC
)let middleHeigitC
= NSLayoutConstraint.init(item
: middleView
, attribute
: NSLayoutConstraint.Attribute.height
, relatedBy
: NSLayoutConstraint.Relation.equal, toItem
: topView
, attribute
: NSLayoutConstraint.Attribute.height
, multiplier
: 1.0, constant
: 0)view
.addConstraint(middleHeigitC
)let bottomVC
= NSLayoutConstraint.constraints(withVisualFormat
: "V:[middleView]-[bottomView]-0-|", options
: [], metrics
: nil, views
: ["middleView":middleView
,"bottomView":bottomView
])view
.addConstraints(bottomVC
)let bottomHC
= NSLayoutConstraint.constraints(withVisualFormat
: "H:|-0-[bottomView]-0-|", options
: [], metrics
: nil, views
: ["bottomView":bottomView
])view
.addConstraints(bottomHC
)
- 給下面藍色視圖添加一個UILabel,使其上左右邊距為10,高度自適應
let label
= UILabel()label
.translatesAutoresizingMaskIntoConstraints
= falselabel
.font
= UIFont.systemFont(ofSize
: 15)label
.numberOfLines
= 0;label
.backgroundColor
= UIColor.cyanbottomView
.addSubview(label
)let labelHC
= NSLayoutConstraint.constraints(withVisualFormat
: "H:|-10-[label]-10-|", options
: [], metrics
: nil, views
: ["label":label
])bottomView
.addConstraints(labelHC
)let labelVC
= NSLayoutConstraint.constraints(withVisualFormat
: "V:|-10-[label]", options
: [], metrics
: nil, views
: ["label":label
])bottomView
.addConstraints(labelVC
)label
.text
= "lalalalalaz汽車消費網lalalalalaz汽車消費網lalalalalaz三生三世lalalalalaz汽車消費網lalalalalaz汽車消費網lalalalalaz三生三世vlalalalalaz汽車消費網lalalalalaz汽車消費網lalalalalaz三生三世lalalalalaz汽車消費網lalalalalaz汽車消費網lalalalalaz三生三lalalalaz汽車消費網lalalalalaz汽車消費網lalalalalaz三生三世lalalalalaz汽車消費網lalalalalaz汽車消費網lalalalalaz三生三世vlalalalalaz汽車消費網lalalalalaz汽車消費網lalalalalaz三生三世lalalalalaz汽車消費網lalalalalaz汽車消費網lalalalalaz三生三lalalalaz汽車消費網lalalalalaz汽車消費網lalalalalaz三生三世lalalalalaz汽車消費網lalalalalaz汽車消費網lalalalalaz三生三世vlalalalalaz汽車消費網lalalalalaz汽車消費網lalalalalaz三生三世lalalalalaz汽車消費網lalalalalaz汽車消費網lalalalalaz三生三lalalalaz汽車消費網lalalalalaz汽車消費網lalalalalaz三生三世lalalalalaz汽車消費網lalalalalaz汽車消費網lalalalalaz三生三世vlalalalalaz汽車消費網lalalalalaz汽車消費網lalalalalaz三生三世lalalalalaz汽車消費網lalalalalaz汽車消費網lalalalalaz三生三lalalalaz汽車消費網lalalalalaz汽車消費網lalalalalaz三生三世lalalalalaz汽車消費網lalalalalaz汽車消費網lalalalalaz三生三世vlalalalalaz汽車消費網lalalalalaz汽車消費網lalalalalaz三生三世lalalalalaz汽車消費網lalalalalaz汽車消費網lalalalalaz三生三lalalalaz汽車消費網lalalalalaz汽車消費網lalalalalaz三生三世lalalalalaz汽車消費網lalalalalaz汽車消費網lalalalalaz三生三世vlalalalalaz汽車消費網lalalalalaz汽車消費網lalalalalaz三生三世"print(bottomView
.constraints
)
UIView.animate(withDuration
: 3) {
self.label
.layoutIfNeeded()}
extension ViewController {override func touchesBegan(_ touches
: Set<UITouch>, with event
: UIEvent?) {let labelHC1
= NSLayoutConstraint.constraints(withVisualFormat
: "H:|-60-[label]-60-|", options
: [], metrics
: nil, views
: ["label":label
])bottomView
.removeConstraints(labelHC
!)bottomView
.addConstraints(labelHC1
)UIView.animate(withDuration
: 3) {
self.bottomView
.layoutIfNeeded()
}}
}
小結
- 上面可以看出:NSLayoutConstraint的constraints方法是通過VFL添加水平和垂直方向約束來進行自動布局,而NSLayoutConstraint的便利構造方法是通過添加上下左右間距或間距和大小來添加約束來自動布局,兩者單獨使用或結合使用都可以,各有優缺點,一般會結合使用.
open
class func constraints(withVisualFormat format
: String, options opts
: NSLayoutConstraint.FormatOptions = [], metrics
: [String : Any]?, views
: [String : Any]) -> [NSLayoutConstraint]
public convenience init(item view1
: Any, attribute attr1
: NSLayoutConstraint.Attribute, relatedBy relation
: NSLayoutConstraint.Relation, toItem view2
: Any?, attribute attr2
: NSLayoutConstraint.Attribute, multiplier
: CGFloat, constant c
: CGFloat)
-
oc 中 NSDictionaryOfVariableBindings(v1,v2,v3)宏相當于[NSDictionary dictionaryWithObjectsAndKeys:v1,@“v1”,v2,@“v2”,v3,@“v3”,nil]
-
父控件是誰,這些約束就添加給誰.
-
UIView的open var translatesAutoresizingMaskIntoConstraints: Bool屬性,把 autoresizingMask 轉換為 Constraints,即:可以把 frame ,bouds,center 方式布局的視圖自動轉化為約束形式。(此時該視圖上約束已經足夠 不需要手動去添加別的約束).
-
用代碼創建的所有view , translatesAutoresizingMaskIntoConstraints 默認是 true,用 IB 創建的所有 view ,translatesAutoresizingMaskIntoConstraints 默認是 false . 如果用代碼約束布局,則需要將該屬性設置為false.
-
translatesAutoresizingMaskIntoConstraints屬性autoresize布局:true,autolayout布局 :false`.
-
在更新約束時,要先刪除一些約束removeConstraints,再添加對應的一些約束addConstraints,然后跟新約束才有有效.
-
項目開發過程中,通常使用的是Masonry\SnapKit自動布局的三方庫,簡單高效。較之frame布局,自動布局更適合業務拓展。
基于約束的AutoLayer更新約束的方法
1、setNeedsUpdateConstraints
當一個自定義view的某個屬性發生改變,并且可能影響到constraint時,需要調用此方法去標記constraints需要在未來的某個點更新,系統然后調用updateConstraints.
2、needsUpdateConstraints
constraint-based layout system使用此返回值去決定是否需要調用updateConstraints作為正常布局過程的一部分。
3、updateConstraintsIfNeeded
立即觸發約束更新,自動更新布局。
4、updateConstraints
自定義view應該重寫此方法在其中建立constraints. 注意:要在實現在最后調用[super updateConstraints]
uto Layout Process 自動布局過程
與使用springs and struts(autoresizingMask)比較,Auto layout在view顯示之前,多引入了兩個步驟:updating constraints 和laying out views。每一個步驟都依賴于上一個。display依賴layout,而layout依賴updating constraints。 updating constraints->layout->display
第一步:updating constraints,被稱為測量階段,其從下向上(from subview to super view),為下一步layout準備信息。可以通過調用方法setNeedUpdateConstraints去觸發此步。constraints的改變也會自動的觸發此步。但是,當你自定義view的時候,如果一些改變可能會影響到布局的時候,通常需要自己去通知Auto layout,updateConstraintsIfNeeded。
自定義view的話,通常可以重寫updateConstraints方法,在其中可以添加view需要的局部的contraints。
第二步:layout,其從上向下(from super view to subview),此步主要應用上一步的信息去設置view的center和bounds。可以通過調用setNeedsLayout去觸發此步驟,此方法不會立即應用layout。如果想要系統立即的更新layout,可以調用layoutIfNeeded。另外,自定義view可以重寫方法layoutSubViews來在layout的工程中得到更多的定制化效果。
第三步:display,此步時把view渲染到屏幕上,它與你是否使用Auto layout無關,其操作是從上向下(from super view to subview),通過調用setNeedsDisplay觸發,
因為每一步都依賴前一步,因此一個display可能會觸發layout,當有任何layout沒有被處理的時候,同理,layout可能會觸發updating constraints,當constraint system更新改變的時候。
需要注意的是,這三步不是單向的,constraint-based layout是一個迭代的過程,layout過程中,可能去改變constraints,有一次觸發updating constraints,進行一輪layout過程。
注意:如果你每一次調用自定義layoutSubviews都會導致另一個布局傳遞,那么你將會陷入一個無限循環中。
相關參考
-
VFL的簡單使用教程
-
iOS-手動添加限制-constraintsWithVisualForm
-
translatesAutoresizingMaskIntoConstraints 詳解
-
自動布局之-NSLayoutConstraint
-
Autoresize和Autolayout 布局的實現
-
iOS AutoLayout全解
-
setNeedsUpdateConstraints,needsUpdateConstraints等基于約束的AutoLayer的方法
-
ios – setNeedsLayout vs. setNeedsUpdateConstraints and layoutIfNeeded vs updateConstraintsIfNeeded
-
MY_updateConstraintsIfNeeded,setNeedsLayout, layoutIfNeeded 和 layoutSubviews 方法之間的關系解釋
-
iOS自動約束】四個重要的系統方法
-
UIStackView
-
Stack
-
相關源碼(包括AutoLayout,Masonry,SnapKit):AutoLayoutStudy
總結
以上是生活随笔為你收集整理的iOS AutoLayout的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。