前言
很久沒用autolayout,一直用的masonry,再用autolayout,很生疏,寫一篇文章,作為手記。
碼字較多,確實令人不想看,希望看到的小伙伴認真讀一下.
masonry
個人比較喜歡標哥關于masonry的見解:博客
sb,xib
具體sb,xib的細節(jié)這里就不多了解了。下面推薦一篇文章,看下就行了
xib 使用
xib 原理
這篇文章不錯,至少之前沒有了解到這一點
xib 轉代碼
這里xib轉純代碼,覺得沒多大意義,復雜頁面轉后,會想吐的。不過了解一下也好,初學者,可以將ib視圖轉為代碼,學習控件如何使用的。
xib 約束
視圖約束,不管masonry還是AutoLayout。深入理解約束一詞的意思,萬變不離其宗。即把一個視圖束縛在一個地方,當頁面變化時候,視圖不會亂跑。視圖變化只有“上下左右”四個維度,仔細理解寬高的變化其實也是上下左右中的變化,所以,怎樣束縛一個視圖?
1:確定origin:{x, y}
2:確定frame:{width, height},或確定右邊下邊,也相當于確定了寬高。
所有就會有各種組合:
上左下右
上左寬高
左寬centerY高
centerXY寬高
。。。
autolayout
關于autolayout的基本了解,這里不多說,推薦簡書-一天一點xib系列
控件集

看這一大片,實際項目中,能用40%就不錯了,這篇文章就揀一些常用的了解
顯示區(qū)

這里能看到左邊是視圖層次結構和約束,中間是可視化頁面,右邊是布局操作區(qū)。點點看,沒多少東西
約束操作區(qū)

開發(fā)中,常用的也就右下角那幾組約束功能。一直用的都是他們
第一個標簽
Update Frames.單一功能,就是恢復視圖原布局的。跟git上的reset、svn的revert差不多,理解成返回就行了
第二個標簽
Embed In Stack.這是Xcode7在iOS9引入的新功能,它用來統(tǒng)一管理它所有的subView(子視圖)上的約束.相當于一個容器view用來統(tǒng)一管理他所有subView的約束,其實普通的UIView也可以作為容器view來管理其subView的約束,我們之前做復雜UI顯示邏輯的時候往往也會放一個背景的容器view,stack view就是起到這個作用,意義不是很大,它做的事情UIView也可以做,但是他的優(yōu)勢在于:可以通過設置屬性的方式讓系統(tǒng)自動添加對其subView的約束,而且該view是不渲染在頁面上的,對它設置背景色等屬性是無效的...(對android有了解的,這個跟merge差不多)
第三個標簽
Align.用于添加多個控件間對齊關系,從上到下依次是左對齊、右對齊、上對齊、下對齊、水平對齊、豎直對齊,這些現(xiàn)在都是灰色的不能選擇,只有同時選中多個控件,他們才是可用的,或者先選擇一個控件,然后按住control拖動到另一個控件上,就會彈出一個控件對齊的窗口,可以在里面設置兩個控件的對齊關系。下面兩個是相對于superView設置水平、豎直居中,選中單個控件就可以設置
第四個標簽
Add New Constraints.用于對單個控件設置約束,上面的四個框分別填寫上下左右的約束,注意,每個框右側的三角是可以點擊出菜單進行選擇的,比如有A、B、C三個控件,A、B同在C的左側,對C設置左側約束的時是可以選擇針對A還是B進行計算的,如果通過auto layout設置的約束與顯示的結果不符的時候,可以點擊三角檢查是不是設置約束的參照對象選錯了。
Constrain to margins選項的解釋:
當拖動一個控件到另一個控件里時,作為super的控件會有幾條參考線(藍色虛線,如果你使用的硬件是帶有Force Touch觸控板,且使用的xcode7的時候,拖動到參考線處的時候觸控板會輕微震動,發(fā)出機械上的一個聲音以給你反饋),上下左右四個方向的邊緣會有,水平、豎直的中心處會有。
若勾選Constrain to margins實際super與sub之間的參考邊緣就是這些參考線,而不是實際的super的frame的邊緣,如果我們不勾選的話就是以frame的邊緣為參考。
下面的Width、Height是限制自身寬高的選項。
Equal Widths、Equal Heights是與其他控件保持相同的寬高,默認是灰色不可用狀態(tài),只有選擇兩個以上的控件,才可使設置,同樣也可以先選中一個控件,按住control拖動,彈出的窗口中也有該選項。Aspect Ratio 是設置自身的寬高比的。
Align選項同樣是設置兩個以上控件的對齊關系的。
Update Frames一般是用來更新frame的。我們設置的約束如果與當前控件的frame產(chǎn)生沖突的時候就要解決沖突,要么修改約束,要么修改frame,最后使系統(tǒng)可以沒有歧義的確定UI布局,有沖突的時候會在xib左邊欄的右上角顯示警告或錯誤的標識,我們點擊標識,按照系統(tǒng)提供的沖突解決方法就可以解決沖突。
第五個標簽
Resolve autoLayout issue.這個標簽主要用于重新設置autolayout.這個標簽可以作用在選中的view或者是以這個view為父視圖的所有view
比如:Update Frame,用于更新UI,比如我們設置了自動適應布局,可以用這個選項來更新它的位置.
Clear Constraint,用于清空所有的約束.
注意
如果我們使用了autoLayout自動布局,那么我們在ViewDidLoad和iOS5之后新加入的ViewWillLayoutSubviews中修改Frame均不能生效.這是因為,ViewWillLayoutSubviews這個方法在ViewDidLoad之后調用,也就是說frame生效之后接著就被autoLayout給重新布局了.
既然這樣那么,我們要更改frame就要在ViewDidLayoutSubviews中更改,或者將自動布局拖成屬性,在代碼中更改.
屬性設置區(qū)

這里面絕大部分設置,用純代碼都能編寫。所以,這里設置,轉為純代碼,去了解學習控件屬性知識也是不錯的辦法
第一個標簽
show the file inspector.這個標簽主要介紹xib文件的基本信息,一般是不會用到的,所以也不用修改.
第二個標簽
show quick help inspector.這個標簽就是一些快捷幫助信息,基本上就是蘋果API中對某個控件的介紹.
第三個標簽
show the identity inspector.在這個標簽下主要做一些標識.我們最常用的就是其中的Custom Class,用這個標簽來關聯(lián)xib文件與我們自己創(chuàng)建的類文件
第四個標簽
show the attributes inspector.在這個標簽使我們最常用的一個標簽,我們通常會使用它進行控件的屬性設置.比如設置模擬器的一些尺度,顏色等相關的.這個標簽的內容(即可設置的屬性)會因控件的不同而變化的.
第五個標簽
show the size inspector.這個標簽是設置frame的相關,主要與尺寸相關.
第六個標簽
show the connections inspector.這個標簽主要負責xib文件與類的源文件交互,通俗的將就是"連線",在xib中控件的屬性與觸發(fā)的動作,都是可以拖一條線到類的源文件中,用代碼進行下步操作的.這會在接下來進行介紹.
實踐出真知
下面通過項目中常用的控件約束逐一講解xib中autolayout的使用
label
一般約束
第一次使用autolayout,先拖一個label試試
這是xib中autolayout布局的一個label,整個操作如圖。

這是用三方約束庫masonry進行約束的,看代碼,剛設置的background和text用純代碼寫都是一一對應的,所以,這里告訴你,xcode的可視化ui布局做的很棒,開發(fā)中一般用到的視圖屬性設置,這里都能找到設置的地方

這是用最古老的純代碼編寫ui布局。看下代碼量,如果寫個稍微復雜點的頁面,是不是會覺得不爽。

從上面可以看出,純代碼開發(fā)的,就不過多討論了,比較masonry和autolayout布局。用哪個呢?autolayout能快masonry幾條街吧。
最后,針對剛入門的ios開發(fā)來說,建議先masonry,再autolayout。因為autolayout的實現(xiàn),你并不知道oc代碼的具體實現(xiàn),不利于修煉內功。(當然,外包的話,你是沒有那個條件的,只能用autolayout,只為快,只是重復)
內邊距需求
項目中l(wèi)abel一般clear背景展示內容,很少有內景色的,但是如果美工設計需要有內邊距的。但是autolayout中并沒有內邊距設置呀?

看到label的attributed類型是不是有點聯(lián)想,我們代碼實現(xiàn)label的行間距,字體顏色等富文本設置的時候,用的就是這里的一些東西。但是沒有找到能設置內邊距的。這種需求可以通過自定義label實現(xiàn),如下:
實踐后發(fā)現(xiàn),這種方式內容是顯示不全的,這里沒有深究,有搞過的朋友,可以留言交流。。。?

總結:
uilable 自適應高度,是不帶內邊距的。如果非要實現(xiàn)上面的方案也有,只是內容顯示不全。使用TextView是完美的替代方案。下面會講textview的用法
補充
如果 nib 或 storyboard 里用了 autoLayout,實際運行順序是先執(zhí)行viewDidLoad再執(zhí)行 autoLayout
定制邊框需求
視圖的邊框需求,在項目中大多會用到,我們一般處理方式為view.layer的操作。但是autolayout如何實現(xiàn)呢?
User Defined Runtime Attritubes:用戶定義運行時屬性

key path。有些感觸吧,oc的kvc編碼,所以,對象的屬性都可以在這里試試看。只是有些特例無法直接實現(xiàn),如boder.color。。
注意: runtime,看到了吧,所以,xib中是無法可視化的。運行起來才能看到效果。
特例:設置邊框顏色
layer.borderColor type里只有Color 沒有CGColor。
解決:CALayer分類 提供方法:transeColor2CGColor:(UIColor *)color。方法寫不寫在.h里面都無所謂
使用:layer.transeColor2CGColor
注意:正常來講,分類里是沒有屬性的,但是在使用時候,就當有屬性使用,所以,方法名一般為setAbc。然后xib中設置時候使用是abc,如下:


實際操作時候,盡量還是用copy,手敲的話,很容易手誤,又很難發(fā)現(xiàn)。如果設置錯誤,系統(tǒng)默認為黑色。
textview
高度自適應需求
針對label,textview等需要根據(jù)文本內容,高度自適應,可以使用純代碼計算內容高度,但是大家應該也比較詬病這種方法,諸如開發(fā)麻煩,計算不準等。使用autolayout相對來說有種方案就簡單多了,如下:

看效果:

這里有兩點注意:
1:設置過后,看上圖,高度約束變虛線了。
2:用過masonry都知道,每條約束都有優(yōu)先級,因為masonry也是封裝的NALyoutConstraint嘛,看下圖,不解釋。


總結:
在內容自適應高度的布局需求中,這種布局方式也是一大利器。請善用
1:有內邊距
2:內容默認吸頂
3:如果需要自適應高度,調整高度自適應,不讓滾動即可實現(xiàn)
需求拓展
在實際開發(fā)中,textview不能一直隨著內容增高,會有一個最大高度。實際開發(fā)中,我們一般使用封裝好的自定義textview。如下,這里講autolayout,不過多的了解如何自定義
button
通過上面label的練習,大部分單個視圖的約束操作都是能應對的。下面以button為實例,了解一下不同狀態(tài)的練習。
button 基本設置:背景色、背景圖片、圖片、標題、圓角、狀態(tài):正常,高亮,選中,等
多操作,熟能生巧,xib中ui布局都是操作性的
imageview
imageview基本操作這里就略了,跟上面一樣,下面說一些進階的:
imageview添加子視圖
沒有實際操作過的,并不覺得這里有什么,坑點就是imageview上沒法添加子視圖。純代碼你也可以實踐試試。下面說下xib如何實現(xiàn):

imageview 添加子視圖:拖拽uiview視圖,class 改為imageview,由于是UIView,要在.m中設置圖片
總結:
碰到視圖嵌套的需求,如果父視圖不支持嵌套,可以試試這么干。把UIView轉為對應子類型
tableview
終于說到tableview,初入門ios的,感覺tableview有些懵逼吧,什么協(xié)議,代理,數(shù)據(jù)源等一些新名詞,整的費解。不過,這里說的是布局,嘿嘿
展示全部內容
tableview本身是可以滾動的,如果cell不多,想展示全部內容共,讓tableview根據(jù)cell自適應高度。參考下面collectionview部分。demo中有實現(xiàn)。
cell自適應高度
我們實際開發(fā)中共,cell自適應高度一般使用的都是三方庫:
xib布局對應:UITableView-FDTemplateLayoutCell
masonry布局對應:HYBMasonryAutoCellHeight
這里了解一下,不用三方庫,實現(xiàn)cell自適應高度的操作:self-sizing cell,實在不想碼字了,看demo實踐
collectionview
如何顯示collectionview全部內容這里有個論題,可以看看。實踐發(fā)現(xiàn),方案如下:
方案:
collectionView的contentSize.height賦給collectionView的高度約束。
總結:
collectionview作為復雜頁面的子視圖,如果需要展示全部cell,這種方案是比較好的。tableview也同樣道理。如果有需求,就可以這么干。。
1:設置collectionview不可滾動
2:設置collectionview高度約束
注意:獲取contentSize一定要在cell加載完成后,不然獲取到為0。collectionview是不會顯示的,cell也不會加載。
scrollview
開發(fā)中,有些頁面,無規(guī)律沒法用tableview,但是有很長,超過了屏幕,我們首選scrollview。說到scrollview,感覺是比較難用的,特別是masonry布局時候,有些麻煩。這里了解一下,提供一個不錯的方案。
scrollview約束
因為scrollview是可以滾動的,所以有個自身的frame,還有個并不存在的contentview,就是scrollview里的子視圖們。想象一下放映機,放映口和膠片。放映口相當于scrollview的frame,膠片相當于scrollview內的內容。一旦膠片長度超過放映口。是不是就有滑動的觀感了。tableview和collectionview和textview都是繼承自scrollview,所以,都是同樣的道理。如何實現(xiàn)?原理就是scrollview添加containerview。子視圖們撐開containerview,將constainerview的size作為scrollview的contentsize。
目的:確定 scrollview 的 contentSize
三步:
1:添加scrollview,并約束
2:添加containerview,并約束

理想情況這里應該正常的啊,然而,看一下約束錯誤。表示scrollview沒法確定x方向的position或width,和y方向的position或height。
3:約束解決
我們目的是確定scrollview的contentsize。那么即是確定containerview的size{width,height}和origin{x,y}。如下:
1):width。同scrollview的frame的width即可。已經(jīng)約束過
2):xposition/width。假設需求是豎直滾動。那么設置水平居中是最合理的。因為scrollview中content的左右相對約束點你都不知道。containerview的左右相對scrollview已經(jīng)約束過,怎樣組合,水平方向才能束縛住containerview不亂跑呢?一是設置containerview的width,二是水平居中,試試看:

3):yposition/height。由于需求是豎直滾動,所以,不能豎直居中,只能約束containerview的height。

scrollview滑動
以上scrollview的約束做過了。知道原理,scrollview以什么樣的frame存在或嵌套都是可以應對的。西面了解下開發(fā)中常見的場景:
subviews超過一屏,使用scrollview實現(xiàn)滾動:
方案:手動計算更新containerview的height約束。
這種虛擬器窗口不能變動

調整metrix

調整虛擬窗口,拉大高度

手動計算-動態(tài)設置containerview的高度

控件平分
上面了解了單個視圖的布局。下面了解一下多視圖組合布局的技能。
需求:視圖等寬等間距平分父視圖

比例布局
實際開發(fā)中,比例布局用的感覺不是很多。這里也了解一下:


這個第二類約束,解釋一下:
約束過紅view的寬高ratio后,約束報錯,是因為已經(jīng)約束了寬高,現(xiàn)在又約束寬高比1:2,跟原寬高比不一樣,所以,刪除寬高的任一約束即可。
組合批量處理
先看個錯誤的栗子。

green的view為啥跑到前面去了呢?而不是4個view左右平分??聪耮reen視圖的相對約束,發(fā)現(xiàn)是相對于safe area。為啥呢 ?因為干剛開始放的時候,green視圖就非常靠上,該視圖左右能看到的第一個視圖就是safe area。所以,就這樣了。這也是autolayout方便的一點,默認視圖依賴,下面看正確的處理。。

解釋一下:組合批量處理分3個步驟:
1:預先處理
上面錯誤例子演示了,首先要把幾個視圖放到差不多的位置,然后再進行整體處理
2:劃整體處理
將視圖組處理為一個整體:
1:水平對齊
2:左右平分,等寬等高
3:整體約束
上面將視圖化為一個整體了,剩下的,就單選任一個視圖,確定yposition/height即可。這里操作的是blue視圖,topSpace和height。這樣就確定了每個視圖的上下左右或寬高四個約束了
組合自適應布局
這種布局的場景一時沒想起來,沒遇到過。這里就不多了解了。推薦一篇好文:
子視圖撐開父視圖
這類布局需求太常見了,總想有騷操作來實現(xiàn),實際開發(fā)中總是用笨方法,計算子視圖高,更新父視圖高。這一點都不智能啊:用autolayout下面有一種方法,一起了解一下:

解釋:
高度自適應
設置約束,記住規(guī)則:先父后子,父無高需自適,子一一約束四方,最后父依賴最底視圖的底部。
圖中的子視圖,由于自適應內容,所以特殊設置了高,priority。上面label,textview有了解過。
priority設置多大?
系統(tǒng)提供的有Required:1000,High:750,Low:250。這里設置時候取值范圍:0 < x < 750 & x != 250。
看效果:

基于Object封裝
推薦文章。。這里有了解object的使用。我也是照著實踐的,所以,就不搬磚了
基于UIView封裝
基于UIView封裝xib: xib 還沒那么強大:
1:如果想實現(xiàn)vc.xib自動初始化customview。那么,vc和view就沒法共用view中的交互
封裝自定義view步驟
1):customview.xib不設置同名class
2):customview.xib設置file's owner為同名cutomview類
3):在vc.xib直接使用view視圖,設置class為customview即可
2:如果想實現(xiàn)vc和customview共用customview中的交互。那么,vc中需要手動加載customview.xib。并約束。
封裝自定義view步驟
1):customview.xib設置同名class
2):customview.xib設置file's owner為所在vc類
3):在vc中加載customview.xib。按需約束。
1):約束不能和vc.xib統(tǒng)一約束,可以masonry和autolayout共同約束,所以,一般可用在單一約束上,沒有其他customview的相對約束,比如:tableview的headerview。
2):customview.xib不能放到customview中initwithcoder進行初始化加載。只能使用的地方手動加載。因為:customview.xib的file's owner是vc
沒有圖示,是不是看的云里霧里的。真正實踐過的,應該知道我在說什么??吹竭@里的有興趣的朋友,一起交流。
需求完善
上面說了想要封裝customview。并且vc中自動初始化customview,并且vc中能聲明customview中控件的IBOutlet。其實vc和customview能共用customview中控件的交互已經(jīng)很耦合了。還想在vc中開控制customview中的控件,這還要封裝customview干嘛。
上面說封裝customview后,在vc中使用,還要手動加載。費勁,這里引入一個三方庫技術:XXNibBridge
使用很簡單,解決需求也很給力,看demo。
問題:
1、用了XXNibBridge嵌套的view會創(chuàng)建兩次,第一次會被釋放
2、用了XXNibBridge嵌套的view就不能再用Masonry來做約束
3、vc中不能引入customview的控件。會崩潰,沒深入研究
4、loadNibNamed手動加載customview.xib文件,沒有父視圖。
作者很久沒有維護了。如果要使用該庫,項目中各種場景還是要驗證過再用,不然有坑就尷尬了。一般的使用還是完全可以勝任的
xib 高深用法
這里詳細講解了xib一些高端用法,個人了解較少,就不亂說了
IB_DESIGNABLE
IB 動態(tài)渲染。
上文里了解了IB_DESIGNABLE的用法和作用,但是那種方式只是將視圖的處理封裝到自定義視圖中,可以在xib中使用,但是沒法動態(tài)可視化操作。
可視化操作,動態(tài)渲染方案
IBInspectable + IB_DESIGNABLE:可視化動態(tài)渲染視圖
IBInspectable讓支持KVC的屬性能夠在Attribute Inspector中配置
IB_DESIGNABLE的宏的功能就是讓XCode動態(tài)渲染出該類圖形化界面
坑點:
IBInspectable:
布爾類型:BOOL,不能是Boolean
支持類型:屬性支持kvc的:Boolean,Number,String, Localized String, Point, Size, Rect, Range, Color, Image, Nil;
IB_DESIGNABLE:
IBInspectable標記的屬性,要重寫set方法。才能可視化。。。不能重寫get方法。會報錯
這里以cornerRadius實踐:

IBInspectable標記的屬性會在這里顯示,可操作。

User Defined Runtime Attritubes。這里的值,是你操作IBInspectable標記的屬性后,這里動態(tài)顯示,沒有操作過的,不會顯示。重點是:就算你操作了,也只有IB_DESIGNABLE標記的.m文件重寫了set方法的屬性有效。

看到?jīng)],這里只操作了radius和color,上面User Defined Runtime Attritubes中就只限是了radius和color

總結
一起了解了autolayout的一些基本和進階用法,autolayout操作都是技能性的,多練習就ok了。這里不能窮舉所有的用法,學會自己摸索,根據(jù)約束錯誤提示,練習自己的約束方案和習慣