標籤:
本文轉自 http://ruikq.github.io/ios/autolayout/uiscrollview/2015/01/27/iOS-autolayout%E6%80%BB%E7%BB%93.html autolayout, and uiscrollview
以前學習iOS的時候沒怎麼接觸過autoLayout,自從iPhone6個6+出來之後一直在為以前的app做適配,所以使用了大量的autoLayout做適配,一開始很不習慣,但是越用越覺得好用,接觸到現在遇到很多問題,在這裡總結一下,包括三部分:限制的優先順序、autoLayout下得UIScrollView和UITableView。
優先順序
在一開始autoLayout的使用過程中,優先順序常常是被我所忽略掉的,所以有的時候在一些稍微複雜的布局中往往會出現一些很奇怪的問題和警告,尤其是布局一些大小隨內容改變的控制項時(UIButton、UILabel、UIImageView),而這些問題和警告都可以通過優先順序來解決,下面以UILabel為例子來總結一下:
以上是UILabel的限制,都是採用預設的優先順序,當點擊長文字按鈕的時候label上附有長文本,點擊短文字按鈕則是短的文本。
首先看一下Content Hugging Priority以下部分,一開始使用autolayout的時候我是沒有關注到這一部分的。Content Hugging Priority的的意思是限制內容變大優先順序,下面對應橫向和縱向,Content Compression Resistance Priority是限制內容縮小優先順序,最下面的Intrinsic Size則是設定內容固定大小。
為更好理解上述術語的意思,demo中只關注了橫向。運行demo無論點擊長文字還是短文字按鈕label的大小都是不會改變的。下面通過改變一些優先順序來使label大小隨文字大小改變,首先將label的Trailing的限制優先順序改為700,其他不變,然後運行,發現label可隨文字變大但不能變小,這是因為label的右邊距離父視圖的優先順序700小於750,所以Trailing Constrain失效,限制內容變小的限制生效,所以當label內容變多時就限制住label變小,但是Content Hugging Priority的優先順序為251小於700,當文字少時無法阻止label變大,現在改變Content Hugging Priority為800。
出現警告,期望label寬度0,是因為在storyboard設計階段自動計算label文字寬度為0,所以label大小也為0;可以通過設定Intrinsic Size 為PlaceHolder去掉警告,這裡告訴storyboard設定一個臨時佔位尺寸,這個佔位尺寸僅在storyboard設計階段有效,不會影響到運行時的尺寸,運行,現在正常了。
UIScrollView
在autoLayout下,UIScrollView的contentSize是由其中的內容大小來決定的,依賴關係和正常的子視圖依賴父視圖是相反的,所以UIScrollView的子視圖的布局約束是不可以通過UIScrollView來確定的,所以一般情況下的約束到了UIScrollView中就會出現很多錯誤和警告。
要處理這種情況就去要確定UIScrollView中子視圖的寬和高,但是這又和autoLayout下寬、高的可變性衝突,目前的方法是引進一個錨點視圖,子視圖的寬和高根據錨點視圖確定。
anchorViewForWidth是一個寬和父視圖相等,高為0的視圖,contentView的高固定、寬度和anchorViewForWidth相等,我們也必須設定contentView的top、trailing、leading、button,這不影響contentView的大小,這相當於是UIScrollView可捲動區域的旁白,所以像這樣在一般視圖中看上去重複設定限制會發生警告,但在這裡就不會出現。
在縱向滑動的UIScrollView項目中contentView的寬度依賴可以這麼設定,上面的contentView的高度我們是固定的,但如果高度是隨運行時確定的我們就不可以設定固定了,在ios8中像UILabel、UIButton、UIImageView這類大小隨內容改變的控制項我們是不需要設定高度,系統會自動根據內容計算,如果控制項中的內容是動態獲得的,我們可以設定placeHolder佔位尺寸來進行預設定;
設定placeHolder之後
而對於系統無法計算的控制項雖然設定了placeHolder沒有了警告,但是運行時控制項卻不可見,所以只有先設定高度固定再將限制映射為變數,運行時計算修改constant。
UIScrollView中的注意事項
1、有些情況下UIScrollView不能滾動 原因是使用autoLayout之後,在ViewDidLoad之後,系統會重新計算控制項的一些值會導致UIScrollView的ContentSize變為(0,0),所以需要在viewDidLayoutSubViews方法中重新設定UIScrollView的contentSize,但有時在ios7上不行,ios7需要在viewDidAppear:animated方法設定contentSize。
UITableView
在UITableView的cell中使用autoLayout,可以根據內容本身來計算cell的高度,在iOS8中只要將tableView.rowHeight設定為UITableViewAutomaticDimension,系統就會根據cell設定好的約束自動計算出高度,在iOS7中需要使用systemLayoutSizeFittingSize:方法來根據約束計算cell的Size,而在iOS6中我們需要手動計算cell的高度。
UITableView使用autoLayout比UIScrollView要簡單,唯一讓我遇到麻煩的是tableHeaderView,在xib檔案中加入tableHeaderView之後是無法改變他的位置的,也不可使用autoLayout增加約束,這就無法動態改變tableHeaderView的高度;在搜尋了StackOverflow之後發現不需要對tableHeaderView設定autoLayout,想要改變tableHeaderView的高度直接更改frame就可以了。
CGRect headerFrame = self.listView.tableHeaderView.frame;headerFrame.size.height = 47;self.listView.tableHeaderView.frame = headerFrame;[self.listView setTableHeaderView:headerView];self.listView.contentOffset = CGPointZero;
對於將外部自訂的view作為tableHeaderView,不能將frame大小設定在自訂的view中,必須也要和上面一樣重新設定frame,否則會出現tableHeaderView遮擋cell、tableHeaderView展開和顯示不全等奇怪現象。
總結
autoLayout是ios6就提出來的東西,一開始因為體驗差、操作煩用的人很少,但是以後的開發中它是必不可少的,由此我想到了Swift,雖然現在剛剛出現版本還不成熟,但是以後必定是慢慢替代Object_C的,因為蘋果不會出一個雞肋東西。接觸autoLayout以來已經有好幾個月了,也是適配很多UI,autoLayout是一個越用越順手的東西,如果出現奇怪的問題就說明某個點還沒有掌握,需要再去細細學習。最後附上demo代碼。
iOS autoLayout總結