AutoLayout代码布局使用大全—一种全新的布局思想
? ?相信ios8出來之后,不少的ios程序員為了屏幕的適配而煩惱。相信不少的人都知道有AutoLayout
這么個玩意可以做屏幕適配,事實上,AutoLayout不僅僅只是一個為了多屏幕適配的工具,
它真正的意義所在是給了程序員一種全新的布局思想。
? ?本文主要依據(jù)真實項目實例從三個方向全方位講解AutoLayout的使用大全。
? ?一。AutoLayout布局原理和語法
? ?二。約束沖突和AutoLayout動畫處理
? ?三。AutoLayout布局思想,約束鏈的控制。
? ?本文講解的內容和代碼主要依賴于一個名為UIView+AutoLayout的分類。文章末尾將會附上下載鏈接。
? ?一。AutoLayout布局原理和語法
? ? ?筆者在寫這篇文章之前,閱讀過不少關于AutoLayout教程的文章。其中有一句話尤為深刻,
學習AutoLayout之前,必須要完全拋棄傳統(tǒng)的frame屬性,先完成思想的扭轉學習起來方能事半功倍。
? ? ? AutoLayout是蘋果ios6出來的東西,與傳統(tǒng)的Frame屬性不同。每一個view對象都有一個frame屬性,
frame屬于CGrect對象,通過蘋果的Api可以得知,CGrect其實是一個結構體。
struct CGRect {
?CGPoint origin;
?CGSize size;
};
typedef struct CGRect CGRect;一個是控制坐標的CGPoint,一個是控制大小的CGSize。
? ?而AutoLayout是通過約束來實現(xiàn)布局的。一個view一旦使用了AutoLayout約束,
那么它的frame將永遠都是0.
? ?所以在使用AutoLayout之前需要兩個準備工作。
? ?1.設置
translatesAutoresizingMaskIntoConstraints為NO。
? ?2.如果是viewControl則AutoLayout適配寫在
- (void)updateViewConstraints中。
?如果是view則AutoLayout適配寫在
- (void)updateConstraints中。實際上,這也正是AutoLayout好處之一,可以集中將一個controller和
view的適配在一個方法中。
? ?AutoLayout語法主要分三類
? ? 1.設置size。
? ? 先來看看UIView+AutoLayout的實現(xiàn)。
[ViewautoSetDimension:ALDimensionWidthtoSize:30];
? ? UIView+AutoLayout底層原生的實現(xiàn)
?NSLayoutConstraint *constraint = [NSLayoutConstraintconstraintWithItem:selfattribute:NSLayoutAttributeWidth
?relatedBy:NSLayoutRelationEqual?
toItem:nilattribute:NSLayoutAttributeNotAnAttributemultiplier:0.0fconstant:size];
[View?addConstraint:constraint];
? ? 任何一個AutoLayout語法都是通過創(chuàng)建一個NSLayoutConstraint約束對象添加到view的約束中去的。
創(chuàng)建一個AutoLayout需要七個參數(shù),他們分別是(1)WithItem:被約束對象 ?
(2)第一個attribute:被約束對象的關系 ? (3)relatedBy:約束描述 ?(
4)toItem:約束源 ? (5)第二個attribute:約束源的關系 ?(6)multiplier:約束系數(shù)?
?(7)constant:約束常數(shù)
? ? 在官方的api中,對約束有一個計算公式
/* Create constraints explicitly.? Constraints are of the form "view1.attr1 = view2.attr2 * multiplier + constant"?
? ?下面具體講解參數(shù)在NSLayoutConstraint API中的對應屬性。
? ?
typedefNS_ENUM(NSInteger, NSLayoutAttribute) {
? ? NSLayoutAttributeLeft =1,
? ? NSLayoutAttributeRight,
? ? NSLayoutAttributeTop,
? ? NSLayoutAttributeBottom,
? ? NSLayoutAttributeLeading,
? ? NSLayoutAttributeTrailing,
? ? NSLayoutAttributeWidth,
? ? NSLayoutAttributeHeight,
? ? NSLayoutAttributeCenterX,
? ? NSLayoutAttributeCenterY,
? ? NSLayoutAttributeBaseline,
? ? NSLayoutAttributeLastBaseline =NSLayoutAttributeBaseline,
? ? NSLayoutAttributeFirstBaselineNS_ENUM_AVAILABLE_IOS(8_0),
?? ?
?? ?
? ? NSLayoutAttributeLeftMarginNS_ENUM_AVAILABLE_IOS(8_0),
? ? NSLayoutAttributeRightMarginNS_ENUM_AVAILABLE_IOS(8_0),
? ? NSLayoutAttributeTopMarginNS_ENUM_AVAILABLE_IOS(8_0),
? ? NSLayoutAttributeBottomMarginNS_ENUM_AVAILABLE_IOS(8_0),
? ? NSLayoutAttributeLeadingMarginNS_ENUM_AVAILABLE_IOS(8_0),
? ? NSLayoutAttributeTrailingMarginNS_ENUM_AVAILABLE_IOS(8_0),
? ? NSLayoutAttributeCenterXWithinMarginsNS_ENUM_AVAILABLE_IOS(8_0),
? ? NSLayoutAttributeCenterYWithinMarginsNS_ENUM_AVAILABLE_IOS(8_0),
?? ?
? ? NSLayoutAttributeNotAnAttribute =0
};
以上是官方API對約束關系的描述,其中NSLayoutAttributeLeading,NSLayoutAttributeTrailing,實際上等同于left和right,據(jù)說是阿拉伯國家的使用習慣。 ?可以根據(jù)以上枚舉看出約束關系主要就是上下左右,寬度,高度,橫坐標中心,縱坐標中心。
typedefNS_ENUM(NSInteger, NSLayoutRelation) {
? ? NSLayoutRelationLessThanOrEqual = -1,
? ? NSLayoutRelationEqual =0,
? ? NSLayoutRelationGreaterThanOrEqual =1,
};
? 約束描述主要就是<= == >= ?主要是用于不確定大小和坐標的約束,autolayout適配的靈活性和動態(tài)性主要來源于這個約束關系。 ? 約束系數(shù)multiplier和約束常數(shù)constant主要是計算約束關系最終結果的,遵循公式"view1.attr1 = view2.attr2 * multiplier + constant"
? 以上就是所有布局的約束來源,可以看到使用起來非常的方便,由于要想準確的將一個View動態(tài)布局, 有時候往往需要設置好幾個約束來定位view的位置,所以這種代碼寫起來往往比設置frame更加的冗長, 好在文文介紹的UIView+AutoLayout可以替你分擔。 ? ? ? 回歸主題,通過以上代碼可以看到,由于只需要設置一個view的大小,所以不需要約束源,toItem 設為nil,那么約束源的關系自然就是沒有關系了,第二個Attribute設為NSLayoutAttributeNotAnAttribute。 ? ?按照這種思維,其實我們就可以動態(tài)綁定一個view和另一個view的大小,實際上卻很少這么用, 為什么呢?之后會講到。
? ?2.位置間的約束 ? ?先來看看UIView+AutoLayout的實現(xiàn)。 ? ?[View1autoPinEdge:ALEdgeLefttoEdge:ALEdgeLeftofView:View1withOffset:5]; ? ?UIView+AutoLayout底層原生的實現(xiàn)
NSLayoutConstraint *constraint = [NSLayoutConstraintconstraintWithItem:self
attribute:NSLayoutAttributeLeftrelatedBy:NSLayoutRelationEqual
toItem:View2attribute:NSLayoutAttributeLeftmultiplier:1.0fconstant:5];
根據(jù)上文講解的各參數(shù)的含義可知,以上方法的意思就是約束view1的最左邊到view2的最左邊的距離是5(因為約束系數(shù)是1).
3.約束對齊
先來看看UIView+AutoLayout的實現(xiàn)。
[view1autoAlignAxisToSuperviewAxis:ALAxisVertical];
?UIView+AutoLayout底層原生的實現(xiàn)
? ?NSLayoutConstraint *constraint = [NSLayoutConstraintconstraintWithItem:selfattribute:NSLayoutAttributeCenterX?
relatedBy:NSLayoutRelationEqua?toItem:view1.superview
attribute:NSLayoutAttributeCenterXmultiplier:1.0fconstant:0.0f];
根據(jù)上文講解的各參數(shù)的含義可知,以上方法的意思就是約束view1的橫坐標中心在view1的父view中居中.
因為前文說過,所有的約束都是創(chuàng)建一個相同的NSLayoutConstraint對象來實現(xiàn)。所以代碼都是大通小易。
以下主要講解一下UIView+AutoLayout這個分類的使用方法。
根據(jù)以上的約束三種用途,UIView+AutoLayout對應的方法主體上也分為三類。
1.設置size類(以autosetdimension開頭)
以下是ALDimension枚舉
typedefNS_ENUM(NSInteger, ALDimension) {
? ? ALDimensionWidth =NSLayoutAttributeWidth,? ? ?// the width of the view
? ? ALDimensionHeight =NSLayoutAttributeHeight ? ?// the height of the view
};
? 2.位置約束(以autopin開頭)
以下是ALEdge枚舉
typedefNS_ENUM(NSInteger, ALEdge) {
? ? ALEdgeLeft =NSLayoutAttributeLeft, ? ? ? ? ? ?// the left edge of the view
? ? ALEdgeRight =NSLayoutAttributeRight, ? ? ? ? ?// the right edge of the view
? ? ALEdgeTop =NSLayoutAttributeTop, ? ? ? ? ? ? ?// the top edge of the view
? ? ALEdgeBottom = NSLayoutAttributeBottom, ? ? ? ?// the bottom edge of the view
? ? ALEdgeLeading = NSLayoutAttributeLeading, ? ? ?// the leading edge of the view (left edge for left-to-right languages like English, right edge for right-to-left languages like Arabic)
? ? ALEdgeTrailing = NSLayoutAttributeTrailing? ? ?// the trailing edge of the view (right edge for left-to-right languages like English, left edge for right-to-left languages like Arabic)
};
? 3.約束對齊(autoAlign開頭)
以下是ALAxis枚舉
typedefNS_ENUM(NSInteger, ALAxis) {
? ? ALAxisVertical = NSLayoutAttributeCenterX,? ? ?// a vertical line through the center of the view
? ? ALAxisHorizontal = NSLayoutAttributeCenterY,? ?// a horizontal line through the center of the view
? ? ALAxisBaseline = NSLayoutAttributeBaseline? ? ?// a horizontal line at the text baseline (not applicable to all views)
};
第一節(jié)小結:主要講解了一下AutoLayout底層實現(xiàn)原理和UIView+AutoLayout的封裝原理。
?二。AutoLayout約束沖突和動畫處理
?以上的這個頁面就是完全用的AutoLayout布局,整體結構就是這樣,頂部的label1和右上角按鈕button1,
中間的imageview1和label2,下方兩個cellview1和cellview2,再下面一個button2,
最下面的小提示忽略不計。
cellview1和cellview2是自定義的view,里面的一些image view和label都是它的子view。
重點:當一個父view1有了一個子view2,并且子view2有了子view3,那么在約束view3的時候,
如果它的父view不是最高層的那個view,那么view3的約束會對它的父view產生約束影響。 ?
這一個規(guī)則確實讓人很難摸清頭腦,筆者這里不再詳細說明,希望讀者在遇到約束沖突的時候
逐漸摸清這個規(guī)則。
AutoLayout的動畫處理。
假如一個view使用了AutoLayout約束布局之后,這個時候如果對這個view做一個動畫處理,
按照傳統(tǒng)的做法是改變它的一些屬性,在平移動畫中主要是改變它的frame坐標,
但是在AutoLayout中frame都是0應該如何處理呢。這里筆者由難到易提供三種解決方案。
1.使用[self.viewlayoutIfNeeded]方法動態(tài)刷新約束,筆者認為這個對初學AutoLayout的人
來說是最難的。
2.改變view的bounds屬性。這個網上有資料,在AutoLayout中bounds屬性是有效的。
這個可能相對好解決一點。
3.改變view的transform屬性,比如說網上平移10個距離,可以這樣寫self.transform = CGAffineTransformMakeTranslation(0, -10); 相信這個是最簡單也是最好處理的了。
?三。AutoLayout布局思想,約束鏈的控制
??
?還是使用這個頁面加上UIView+AutoLayout來詳細講解。
? ?比如說我要布局cellView1中最左邊那個招商銀行l(wèi)ogo的imageview。
? ?使用UIView+AutoLayout可以這樣寫。
[imageview autoPinEdge:ALEdgeTop toEdge:ALEdgeTop ofView:self withOffset:5];
[imageview autoPinEdge:ALEdgeLeft toEdge:ALEdgeLeft ofView:self withOffset:5];
[imageview autoPinEdge:ALEdgeBottom toEdge:ALEdgeBottom ofView:self withOffset:5];
[imageview autoPinEdge:ALEdgeRight toEdge:ALEdgeLeft ofView:self withOffset:35];
? ?基本上任何的view都可以分別對它的上下左右使用四個位置約束來確定它的位置,
這四行代碼的意思本別就是
? ?imageview頂部距離父view頂部間距5,image view底部距離父view底部間距5,
imageview左側距離父view左側間距5,imageview右側距離父view左側間距35,
? ? 這樣子的話,假如父view的高度是40的話,那么imageview的size不需要設置,
自然而然的被這四個約束為(30,30).
? ? 這看起來沒什么不妥,實際上已經是約束過度了。當父view的高度發(fā)生變更的時候,
imageview的高度就會因為頂部和底部的約束而動態(tài)計算,假如父view高50,
那么imageview的size就是(30,40),這個時候假如是一張方形圖片就會變形,
實際上這并不是AutoLayout的精髓。
? ?
? ? 再看下面這種約束方式
? ??
?[ImageViewautoSetDimensionsToSize:CGSizeMake(30,30)];
?[ImageViewautoPinEdge:ALEdgeLefttoEdge:ALEdgeLeftofView:selfwithOffset:5];
?[ImageViewautoAlignAxisToSuperviewAxis:ALAxisHorizontal];
? ? 這三行代碼的意思是,約束imageview的固定大小(30,30),
約束imageview左側距離父view左側間距為5,約束imageview的縱坐標軸線與父view縱坐標軸線對齊。
通過以上三個約束不難看出,無論父view如果改變大小和位置,
image自身的形狀和父view的相對位置都是固定的。
? ?
? ? 總結:AutoLayout真正的語法只有一個方法,只要理解這個方法的七個參數(shù)分別所代表的含義就不難理解AutoLayout的實現(xiàn)原理。所以對于程序員來說,重要的并不是這種布局方式用代碼寫起來有多么的冗長,因為有不少的三方庫可以幫助你簡寫代碼,實際上我們真正要掌握的是AutoLayout的這種布局思想,心中對一個view布局的時候心中都應該要有一條約束鏈,只有這樣,你的布局約束將會越來越精簡,越來越準確,也越來越適配。
? ?因為筆者自己也是剛剛接觸AutoLayout,以上只是粗略的講解一下自身的學習心得,筆者極力推薦UIView+AutoLayout這個庫來使用AutoLayout,因為封裝都比較形象,并且接近底層,對理解AutoLayout的原理和掌握內涵更加的有益。
? ?以下是三方庫的資源鏈接,http://download.csdn.net/detail/u013263917/8315971?
總結
以上是生活随笔為你收集整理的AutoLayout代码布局使用大全—一种全新的布局思想的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: AutoLayout(自动布局)详细教程
- 下一篇: UILabel上展示不同颜色的文字(NS