AutoLayout:constraint priority 約束優先級(九宮格續,一個更優方案)

原文連接:AutoLayout:constraint priority 約束優先級(九宮格續,一個更優方案)ios

這兩個項目的源碼均在個人 github,若有須要直接下載下來試一試。git

上一篇:AutoLayout:UITableViewCell 自適應高度的一個例子iview

以前由於以爲麻煩,沒有在那個項目裏面嘗試把九宮格圖片分別做爲九個UIImageView來處理(而非一個StackView)。此次我新建了一個項目,來嘗試這種狀況。ide

依然是九宮格格子長寬 75px/75px,單張大圖長寬 200px/200px。函數

效果以下圖。用了一些不一樣的顏色讓各個 view 更明顯。由於我用的圖片背景都是白色,因此我把單張大圖右移了一些以示區分。右邊那一塊白色就是單張大圖。(上下兩塊區域的文字位置沒調好,但這不是重點:D)測試

相同的高度?

一看圖就能發現,單張大圖和九宮格是同樣高的。flex

我用print(onePic.frame.height)單張大圖高度打印下來看,結果是 200.0。沒有問題。ui

難道是九宮格變小了?print(firstImg.frame.height)結果是 75.0。也沒問題。

打印沒成功,因而我測量了一下截圖中九宮格和單張大圖的高度,結果二者都是 233px。這說明單張大圖被拉伸了。

而後我忽然想起print(onePic.image.size.height),打印出來結果是 233.0。圖片果真被拉伸了。

以後我又檢查了一下上次的截圖,發現上次的單張大圖同樣被拉伸到九宮格的高度。

緣由:

此次的模擬是重現上次的解決方案,只是將StackView換成了 9 個獨立的UIImageView

仍是保持了底部的 button panel 與 onePic 和九宮格的間距都是 8px。(此次由於是分離的九個UIImageView,因此設置的是 button panel 和第九章圖片的距離爲 8px, ninethPic)

問題應該就是出在這裏。當 button panel 與 onePic 之間存在這個 8px 的約束時,AutoLayout忽略了設定在 onePic 上固定高寬 200px 的約束,拉伸圖片,使它知足和 button panel 的間距爲 8px。

由於我也是剛接觸 AutoLayout 不久,因此不清楚這樣的狀況是否是在文檔裏面已經寫明瞭,仍是這只是一個實際中發生的狀況須要咱們之後注意。

hidden 只是隱身、不可見,不是徹底消失

上一篇文章最後一部分是:九宮格圖片數量變化時手動適應高度。

當時以爲是由於我用的StackView才致使隱藏下兩排格子以後整個 view 的高度沒有改變。如今我以爲我錯了。

真正的緣由應該是,hidden 只是隱身、不可見,不是徹底消失。這意味着,雖然設置了圖片爲hidden,但其實它仍是在那裏佔位的。因此整個 cell 裏面的各類約束、子視圖間的相對位置不會改變。

那怎麼讓九宮格的高度在格子隱藏以後變小,使得底下的 button panel 能夠向上自適應呢?

第一個辦法是上一篇文章中提到的經過修改constraint.constant

另外一個辦法咱們下面來講。

constraint priority

爲了讓隱藏的 view 完全消失,我趕忙 google 一下。

在這個問題(《AutoLayout with hidden UIViews?》)的回答中找到了有趣的 constraint priority。

被採納的答案用的是提到過的第一個辦法。

得票第二的回答提到了另外一種辦法。

The solution of using a constant 0 when hidden and another constant if you show it again is functional, but it is unsatisfying if your content has a flexible size. You'd need to measure your flexible content and set a constant back. This feels wrong, and has issues if content changes size because of server or UI events.
I have a better solution.
The idea is to set the a 0 height rule to have high priority when we hide the element so that it takes up no autolayout space.

他提到若是你的內容大小是可變化的,那麼修改constraints.constant會很麻煩。這一點我很贊同。

而更好的辦法就是設置 constraint priority

官方文檔:

簡單來講,你能夠給約束設置優先級,它的值在 0 - 1000 之間,優先極高的會先被知足。

好比拿我如今這個例子來講,如今有 button panel - onePic 和 button panel - ninethPic 兩個 8px 間距的約束,分別對應的IBOutletbpAndOnePic以及bpAndNinethPic。假如咱們以下設置:

bpAndOnePic.priority = 1000
bpAndNinethPic.priority = 250

那麼AutoLayout會優先知足 button panel 和 onePic 之間的約束,效果如圖:

能夠看到 button panel 跑到上面去了。單張大圖大小正常了。

實現自動向上適應

九宮格的九張圖片對應的IBOutlet分別爲 firstPic、secondPic、thirdPic、fourthPic…ninethPic;單張大圖爲 onePic;底部 button panel 爲 buttonPanel。

添加 buttonPanel 分別和 onePic、firstPic、fourthPic 以及 seventhPic 之間的 8px 上邊距約束。

bpAndOnePic 是 button panel 和單張大圖之間的約束;bpAndFirstPic 是 button panel 和九宮格第一張圖之間的約束,bpAndFourthPic.priority 和 bpAndSeventhPic.priority 與之相似。(由於是九宮格,因此高度由每排第一張圖存不存在決定。)

有了 constraint priority,咱們能夠這樣設置:

bpAndOnePic.priority = firstPic.hidden ? 1000 : 250
bpAndFirstPic.priority = fourthPic.hidden && seventhPic.hidden && !firstPic.hidden ? 1000 : 250
bpAndFourthPic.priority = !fourthPic.hidden && seventhPic.hidden ? 1000 : 250
bpAndSeventhPic.priority = !seventhPic.hidden ? 1000 : 250

狀況分析

  1. 若是九宮格第一排第一張圖片隱藏了,說明如今是在展現單張大圖(微博沒有附加圖片的狀況咱們在這裏不考慮)。這時bpAndOnePic.priority等於 1000,而bpAndSeventhPic.prioritybpAndFourthPic.prioritybpAndFirstPic.priority都等於 250。bpAndOnePic.priority優先級最高,因此以下圖:

  2. 若是隻有第三排的三張圖片隱藏,那麼bpAndOnePic.prioritybpAndSeventhPic.prioritybpAndFirstPic.priority等於 250,而bpAndFourthPic.priority等於 1000。bpAndFourthPic.priority優先級最高,以下圖:

其餘狀況在此不一一列舉。

這樣既解決了單張大圖被拉伸的問題,又實現了九宮格圖片數量變化時候的向上適應。

待解決:多餘的空白部分怎麼辦?

能夠從上面的截圖上看到,當內容變化的時候,cell 的高度並無變化,因此下方有空白。

以前模仿微博客戶端的項目中,我用了:

func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    return UITableViewAutomaticDimension
}

func tableView(tableView: UITableView, estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    return UITableViewAutomaticDimension
}

它幫我自動去除了空白部分。

我嘗試加上這兩個函數在這個項目中,結果是:

因此下一步我會去搞清楚這個自動計算從新設置高度具體是怎麼回事,解決掉多餘的空白部分。
(另外,我感受這跟我以前的項目 cell 裏包含了 textField 有關 = =)

爲很醜的例子 ui 道歉 = =

相關文章
相關標籤/搜索