2014-10-04 337 views
6

當使用autolayout嘗試使用子視圖填充視圖時,我注意到一些非常奇怪的行爲。這個想法非常簡單:爲視圖添加一個子視圖並使其使用父視圖的所有寬度。Autolayout - 拉伸視圖以填充其父視圖

NSDictionary *views = @{ 
         @"subview":subView, 
         @"parent":self 
         }; 

這不起作用:

[self addConstraints: 
     [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[subview]|" 
               options:0 
               metrics:nil 
               views:views]]; 

子視圖不使用父視圖的整個寬度。

但這個工程:

[self addConstraints: 
     [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[subview(==parent)]|" 
               options:0 
               metrics:nil 
               views:views]]; 

我希望那些打算既會工作。那麼爲什麼第一個例子不起作用?這是蘋果公司建議在以下技術說明:

https://developer.apple.com/library/ios/technotes/tn2154/_index.html

編輯:(去除不相關的信息)

+0

它的工作原理,當我這樣做。你看到了什麼結果?您是否在控制檯中收到任何警告? – rdelmar 2014-10-04 22:59:50

+0

沒有自動佈局警告。子視圖只與其中最寬的元素一樣寬,不佔用父視圖中的所有空間。當我起訴第二個例子時,它工作正常(然後使用所有父視圖的寬度) – 2014-10-04 23:04:31

+0

您需要提供更多信息。你在子視圖中有什麼觀點,你有什麼限制嗎? – rdelmar 2014-10-04 23:08:15

回答

1

如預期被此這是不工作的原因:

父視圖是的UIScrollView,並且水平約束被設置爲"H:|[contentView]|",滾動視圖的contentSize將本身調整至所要求的寬度contentView,而不是相反。因此,自動佈局引擎將首先確定contentView的尺寸,然後將父級(scrollview)的contentSize調整爲相同的寬度。如果contentWidth比父級更窄,它將不會伸展,因爲父級(scrollview)的contentSize將縮小到contentView的大小。

對於普通視圖(不是滾動視圖),父視圖的寬度是固定的,所以它將首先佈局父視圖,然後是子視圖。

通過將contentView的寬度強制爲與父滾動視圖相同的寬度,contentView將始終與父滾動視圖的寬度相同,這正是我想要的(和預期的)。

+0

等等,你是說你實際上看到父視圖縮小到子視圖的寬度了嗎? – algal 2014-10-13 22:52:13

+0

@algal是的,這正是發生的事情。在測試項目中重現非常容易。只需使用約束'H:| [label] |'將UILabel添加到UIScrollView,滾動視圖的內容大小就會縮小到標籤的大小。 – 2014-10-14 22:05:16

+0

好的。所以我沒有我想象的那麼完全錯誤。很高興知道。 TN2154對我來說依然難以理解,儘管我現在至少讀了6次。 – algal 2014-10-14 23:39:44

2

編輯:肯Thomases指出,我完全錯了!

是的,您指定的兩個約束系統都應使parentsubview(或parentcontentView)具有相同的寬度。

所以我會問,你絕對相信你所看到的是contentView未能填補父母?是否有可能在破損的案例中看到父母實際上正在縮小以適應contentView,並且您沒有注意到它,因爲父母具有透明或不可見的背景?

要檢查此問題,請將contentViewparent設置爲具有不同的不透明背景顏色。如果我錯了,你會清楚地看到父區向外擴展的區域,其寬度大於contentView。如果我是對的,contentView將完全覆蓋父級的寬度。

這就是爲什麼我(也許還振振有詞)質疑有關規定實際上你所看到的:

在日誌輸出的主要區別是,對於損壞的案例,我們可以看到,擁有意想不到的約束的UIView到固定寬度的320

<NSLayoutConstraint:0x8433f8f0 'UIView-Encapsulated-Layout-Width' H:[UIView:0x841b9f40(320)]> 

什麼觀點是?基於約束名稱「UIView-Encapsulated-Layout-Width」,它與UIViewControllerWrapperView相關聯,並且寬度保持爲320(iPhone的寬度),我們可以推斷出這個約束是由UIKit自動創建的將UICollectionView.view的大小限制爲屏幕大小。查看所有的約束條件,你可以進一步看到這個width = 320約束是通過一系列約束(封裝視圖 - > DetailView - > DetailWeatherView)傳遞下來的,直到它最終確定了DetalWeatherView的寬度,這是你的parent,並且它使用超視圖邊緣偏移約束來擁抱contentView,因此它也應該具有320的相同寬度。

與此相反,對於有效的情況,您還可以看到應約束contentView.width使其與頂層封裝佈局視圖的寬度相同的約束鏈。但是不同之處在於,任何地方都沒有限制任何固定值爲320的約束。相反,只有左對齊約束。

因此,我希望看到,在這兩種情況下contentView.width == parent.width,但是,在破碎殼體寬度= 320,而在工作情況下,寬度是由低優先級的內部約束內contentView確定允許它膨脹到值大於320,也許是它的intrinsicContentSize。

+1

第二種情況下,你沒有任何限制爲320的寬度。 「WeatherTypeBoxView」和「AdditionalWeatherInfoBox」都被限制爲160寬度並且彼此相鄰並且相互超級視圖的邊緣相鄰。所以,這也修復了寬度爲320的層次結構。我不確定我們能夠顯示多少「額外」限制。我認爲這兩種情況都存在約束,只是它是多餘的。在「-constraintsAffectingLayoutForAxis:'的意義上,佈局系統可能不會考慮冗餘約束來」影響佈局「。 – 2014-10-09 18:39:18

+0

優秀點。 – algal 2014-10-09 18:45:12

4

這裏是你發佈你的「第一例」的約束:

first case

這裏是你發佈你的「第二例」的約束:

second case

我見這些結構有兩個不同之處,我在圖中用紅色突出顯示:

  1. 第一個(損壞的)案例在近根UIView 0x8433f8f0上有一個約束(0x8433f8f0),將其寬度固定爲320個點。這是多餘的,因爲底層視圖每個都限制在160個點,並且有足夠的限制使得這些較窄視圖的所有祖先的寬度爲320個點。

  2. 第二(工作)的情況下具有約束(0x7eb4a670)釘扎的近底部UIView 0x7d5f3fa0的寬度的DetailWeatherView 0x7d5f3270寬度。這個約束是多餘的,因爲3fa0的左邊緣被固定到3270的左邊緣,而3fa0的右邊緣被約束到3fa0的右邊緣。我假設(==parent)謂詞增加了這個約束。

所以你可能會想,每個案例都有一個冗餘約束,那又怎麼樣?沒什麼大不了的,對吧?

不完全。在第二種情況下,冗餘約束確實是無害的。您可以更改WeatherTypeBoxViewAdditionalWeatherInfoBox之一(或兩者)的寬度,並且您仍然可以獲得獨特的解決方案。

在第一種情況下,如果視圖的寬度不變,則冗餘約束僅爲無害。如果更改f8f0上的320寬度約束而不更改葉子視圖上的160寬度約束,那麼約束系統就沒有解決方案。 Autolayout將打破解決該系統的限制條件之一,並且可能會破壞320寬度的限制。我們可以看到320寬度約束及其UIView-Encapsulated-Layout-Width註釋是由系統強制強制這個視圖層次結構符合某個容器的大小(也許是屏幕大小;也許是容器視圖控制器施加的大小)。

我不知道爲什麼你的第一個案件有這個額外的頂級限制,而你的第二個案件沒有。我傾向於相信你改變了導致這種差異的其他東西,但自動佈局足夠神祕,以至於我不能100%相信這一點。

如果您的目標是使此視圖層次結構填充其容器並保持葉視圖的寬度相等,那麼在葉視圖中除去160寬度約束並在它們之間創建一個等寬約束。

+0

正如在關於algal答案的評論中所提到的,我懷疑'UIView-Encapsulated-Layout-Width'約束在兩種情況下都存在。請記住,'-constraintsAffectingLayoutForAxis:'不會返回視圖上的所有約束,它只會返回影響佈局的約束。在冗餘約束的情況下,無論它是否包含,我都認爲是任意的。 – 2014-10-09 19:50:33

+0

我看到了您的評論,但是由於我們正在尋找罪魁禍首,而且這種限制可能會導致佈局問題,所以我現在將其視爲嫌疑人。 – 2014-10-09 19:58:42

+0

如果存在冗餘(但兼容)約束,您確定自動佈局會破壞其中一個約束嗎?我知道如果其中一個約束條件與另一個約束條件相矛盾,那麼這兩個約束條件中的一個將會被刪除,但這對於非矛盾約束條件也是如此嗎?如果是這樣,那可以解釋很多。 – 2014-10-09 20:37:55