iOS發展到如今,iOS5的佔有率已經很低了(估計多數還在使用iOS5系統的用戶活躍度也不高吧),所以兼容最低版本iOS6.0也不會損失太多用戶。同時,下一代大屏iPhone已經發售了,Autolayout絕對是其中一個重要的界面兼容手段。爲了能儘快作好適配好新設備的工做,我相信學習Autolayout這門技術也是必不可少。我做爲一個使用了Autolayout大約一週左右的初學者,就在這裏記錄一下一些要點吧。git
1、Autolayout的簡要背景
Autolayout這個東西是從iOS6開始纔出現的,在沒有Autolayout的遠古年代,你們是用Autoresizing作一些簡單的界面拉伸的。
這裏先說一下Autoresizing,這個東西支持width和height的四方向拉伸,也能夠對x和y作一些簡單的四方向對齊。固然,Autoresizing仍是基於絕對座標的,因此界面上的元素仍是須要設置好對應的座標。支持ib和代碼設置,以下圖
github
1self.view.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight;
能夠看到代碼其實就是設置UIViewAutoresizing枚舉變量,代碼也是比較簡單的。利用Autoresizing就已經能很好適配了搭載iOS6的iPhone5(有部分界面仍是須要多個containerview或者寫代碼手動調節的,不過並不複雜),那爲什麼Apple還要畫蛇添足推出Autolayout呢?
從實用性來看,應對iPhone5之流,Autoresizing足矣,且有兼容性的優點。可是如今時代變了,Android滿地開花的大屏手機(5吋以上才能稱做大屏),Apple爲了保持自有優點,我認爲大屏設備和界面的大一統將會是將來戰略(iPhone可使用原來iPad的專用控件)。這必然致使界面的適配問題,最起碼Autoresizing已經顯得無力了,同時對於部分須要有橫向界面的應用會有更復雜的調整工做。若是不使用Autolayout,改用代碼手工適配的話,工做量也不算少,同時會須要大量的魔術數來定位座標。這徹底不是現代界面該有的開發方式,實在太原始了。隨着iOS8的到來,Autoresizing的兼容性優點會逐漸消失,事實上要同時兼容4個大版本的iOS,這難度的確不小。
所以,如今開始學習並使用Autolayout是一個不錯的時機。除了上述因素,從開發工具來看,對於Autolayout的支持已經比Xcode5以前好了很多。其次,針對Autolayout的開源工具庫也已經相對成熟,前人踩過的坑大多均可以找到對應解決方法。因此,我實在想不出一個拒絕Autolayout的理由。ide
2、Autolayout的基礎知識
若是你們對Android有所瞭解,應該知道他們是經過dp的相對座標和一些佈局來定位控件的(好吧,可能我用詞不太正確)。但iOS的Autolayout思路和Android的佈局思路,仍是有很大的差別。Autolayout的本質是約束,經過設定足夠多的約束條件,來得出每個控件的最終座標。約束條件之間不能相互矛盾,不然會出錯拋出異常。條件之間的矛盾仍是比較難描述的,這個我在下面的內容再舉例說明。
約束的條件有幾種類別:
一、大小(Width、Height、WidthEqually等)
二、間隔(HorizontalSpacing等)
三、對齊(TopEdges、HorizontalCenters等)
在使用Autolayout的界面裏,若是控件不添加任何約束的話,仍是可使用絕對座標定位的。可是,Autoresizing和Autolayout在同一個界面層級是不能共存的,只能選擇其一。不過實際操做上,Autolayout要實現某些Autoresizing的功能是徹底能夠的,可是步驟不必定比之前簡單。
對於一個控件來講,從前的定位是經過設置frame的4個變量來控制的。但在Autolayout的世界裏,這些絕對的數值已經不那麼重要了。Autolayout在運行時計算出這些數值也是須要最少2個約束,大多數狀況還須要4個以上。
2個約束的例子:
系統的UIActivityView是固定大小的,因此只須要添加x和y的約束。
3個約束的例子:
UILabel類控件,其長度能夠由系統計算文字數量和大小得出,因此width或者height的約束能夠省去一個。其他兩個約束就是x和y的約束,具體表現爲HorizontalSpacing等。
4個約束的例子實際上就是多了上述例子一個width或者height約束。
從這些例子,能夠得出一個結論,對於一個控件而言,x和y是不可能避免的約束,因此使用Autolayout的控件最少須要2個約束。固然,大多數狀況是4個約束起步,同時還須要控件間的各類約束來構建一個完整的界面。
同時在Autolayout的光環下,基本再也不須要手動設置frame。使用Autolayout的控件,frame只是表示這個控件當前的座標。只有相關的約束有變化或約束的控件發生變化,隨之這frame也會變化。這些在InterfaceBuilder中能夠很容易體現出來,你能夠當即看到控件在任意狀況下的變化。
3、Autolayout實踐應用
這裏的實踐以ib爲主,我在這裏解釋一下,設置Autolayout實際上有3種方法,分別是:ib、可視語言和傳統代碼。我分別說說這些方法的特色:
一、ib
直觀簡單,所見即所得,實時控制界面變化。系統還會提醒衝突和缺乏約束,並給出修改建議(建議一般不是最好)。對於約束相對靜態的界面,開發效率高。但在複雜頁面中,經常是100+的約束,不是很友好。同時,對界面內的控件複用比較麻煩,形成大量相相似約束。某些控件不能直接往其添加子控件,如UILabel添加一個UIImageView到其中。
二、可視語言
須要編寫代碼,同時要求對Autolayout的體系比較熟悉。因爲其語言樣式能夠比較容易看出控件間的約束關係,因此仍是比傳統代碼直觀,但仍是沒法預想運行時的變化。一次能夠添加多個約束,並在運行時改變約束,可是不能完整實現全部約束功能。同時可視語言也有一些學習成本,沒有對應的代碼建議,因此須要額外的檢查來保證語法正確。
三、傳統代碼
其實就是調用普通的API,參數比較多,可是能夠實現Autolayout的全部功能。從代碼量來看,要比可視語言多。這種方法更偏向於相似傳統code界面,對於一個100+約束的界面,我想仍是挺吃力的。不過,在複用性方面有必定的優點,和可視語言同樣,能夠在運行時改變約束。此外,使用PureLayout開源庫能夠在必定程度上簡化代碼。
做爲新手而言,經過ib來學習Autolayout是最友好的,能夠很直觀地觀察界面的變化。剛開始時,最容易出現的問題就是遺漏了添加一些必要約束,形成指望與實際不符。ib能檢查出約束是否完整,並給予建議,讓新手迅速適應Autolayout的開發。工具
ib會提示警告和錯誤,警告通常不會在運行時產生異常,但錯誤是務必要解決的,由於運行時是必定會有異常的。佈局
出現警告的緣由通常是frame沒有更新,這個能夠直接update一下。性能
而出現錯誤的緣由則是缺乏必要約束或者是約束衝突。前者的解決方法是補全約束,後者的狀況有點複雜。所謂的約束衝突就是沒有辦法同時知足全部約束,從而產生衝突。通常是經過刪除一些約束,使全部約束均可以知足,我的不建議經過修改約束的優先級來解決。如非特殊狀況,通常都是添加越少約束越好,這樣思路越清晰,同時對於運行效率都有必定幫助。從目前經驗來看,通常的界面開發,的確是用不到優先級的(樓主目前的經驗)。
能夠看到這些建議不是惟一的,是選擇其中一個來補全約束的。新手能夠選擇系統的建議,看看補充了什麼約束,但長遠來講,不建議直接使用系統建議補充的約束。我的認爲ib的這些警告和錯誤對於開發界面來講,是極其高效的,但建議卻不是很是智能。特別是補充約束的建議,一般和你心中指望的界面是差距很大的。
對於單個控件,能夠直接經過菜單或者右下角來添加約束,學習
右下角的按鈕還能一下添加多個約束開發工具
對於控件間的約束則須要按住Command+點擊,選中多個控件再添加約束。測試
約束其實也是對象,所以會出如今座標的列表優化
同時,約束也支持outlet
約束爲何也須要outlet?顯然是爲了調用某些方法,而下降了遍歷約束難度。
在ib上拉幾個控件,就能夠完成了上面的簡單實踐了。可是,光這些是不足以完成適配不一樣屏幕的開發。
4、Autolayout的複雜約束
Autolayout中的UILabel類控件大小是自適應的,所以通常不須要指定width和height。並且,固定width和height的這類約束要儘可能少用(UIImageView這類仍是不反對使用),這類約束通常會限制你的思惟。如何多個UILabel並排在同一行,可是行寬有限,同時每一個UILabel都有較多的字數。那麼應該如何控制某個UILabel能夠優先完整顯示?這時就要利用抗拉伸和抗壓縮的優先級了
還有一個相對特別的屬性是比例,支持輸入相似「16:9」這類有無窮小數的值。具體應用以下,
這個約束可使控件跟隨父視圖的大小按比例變化,有相似於以前Autoresizing的效果。
既然約束也是對象,運行動態改變約束的值,則能夠達到更多複雜的控制。爲了操做方便,咱們能夠爲一些約束建立outlet。同時在運行時,根據須要動態改變約束的數值或者移除添加約束等,這時,爲了操做方便,我使用了一個開源庫PureLayout。利用PureLayout就能夠很方便地,對約束進行操做,其API要比系統的友好很多。github地址:https://github.com/smileyborg/PureLayout。
暫時發現的坑:一、在tableView的tableHeaderView使用Autolayout時務必要注意,不要使用嚴格的約束來限制了整個view的大小,不然運行時十有八九會出錯。還有,改變tableView大小時,也有一些錯位的狀況,暫時無解。tableFooterView的狀況未測試,估計應該同樣。二、在iOS6上約束的容錯性更差,更容易報異常,例若有兩個相同約束,iOS6上會有異常斷點,但不會崩潰;iOS7上無任何異常出錯。固然存在多個相同約束是不規範的行爲,編寫約束時應儘可能作到用最少的約束去達到最佳的效果。三、Autolayout也是有性能問題的,目前我在iOS6的iPod Touch4上測試100個左右約束的界面。在刷新tableView和添加視圖等操做時,能明顯感受到延遲。通過一系列操做,甚至會出現1分鐘以上的延遲,這時沒法接受的。能夠得出一個結論,Autolayout在約束較多的時候,在低端機器上也是會形成性能瓶頸的。不過,幸運的是,我在iOS7上的4s運行一樣的界面,就幾乎沒有延遲。隨着低端設備被淘汰,這個問題會獲得緩解的。最後的一個建議是,不要過早地使用Autolayout優化,由於實際上有些界面使用Autoresizing也是能很好地完成適配工做的。同時,對於tableView這類控件使用Autolayout,須要多加留心。