Notes of learning AutoLayout


在XCode5中,如果我們添加一個Button或者Label,或者其他的什么標准View,而不設置任何constraints,IB會自動生成constraints,而這些constraints是fixed,無法根據intrinsic content size的變化而變化,這並不是我們想要的。比如,我在View中添加一個label, label的title是Label,另加一個Button,點擊Button后改變label的title為很長的文字,並且調用invalidateInstrinsicContentSize,在執行前后,分別打印constraints,代碼如下:

    NSLog(@"current constraints %@ ", [[self textLabel] constraintsAffectingLayoutForAxis:UILayoutConstraintAxisHorizontal]);
    NSLog(@"current constraints %@ ", [[self textLabel] constraintsAffectingLayoutForAxis:UILayoutConstraintAxisVertical]);
    
    
    [[self textLabel] setText:@"weuituwjaskdtuqwieotuasdjgakleutaiosgajksdgequwtioasdjgkasjdgkajskgd"];
    [[self textLabel] invalidateIntrinsicContentSize];
    NSLog(@"current constraints %@ ", [[self textLabel] constraintsAffectingLayoutForAxis:UILayoutConstraintAxisHorizontal]);
    NSLog(@"current constraints %@ ", [[self textLabel] constraintsAffectingLayoutForAxis:UILayoutConstraintAxisVertical]);

 這時看到的輸出是

2014-07-04 17:46:28.580 AutoLayoutExample[1110:70b] current constraints (
    "<NSIBPrototypingLayoutConstraint:0x8b95fb0 'IB auto generated at build time for view with fixed frame' H:|-(179)-[UILabel:0x8b93e80](LTR)   (Names: '|':UIView:0x8b95290 )>",
    "<NSIBPrototypingLayoutConstraint:0x8b960e0 'IB auto generated at build time for view with fixed frame' H:[UILabel:0x8b93e80(42)]>"
) 
2014-07-04 17:46:28.582 AutoLayoutExample[1110:70b] current constraints (
    "<NSIBPrototypingLayoutConstraint:0x8b95d60 'IB auto generated at build time for view with fixed frame' V:|-(147)-[UILabel:0x8b93e80]   (Names: '|':UIView:0x8b95290 )>",
    "<NSIBPrototypingLayoutConstraint:0x8b96110 'IB auto generated at build time for view with fixed frame' V:[UILabel:0x8b93e80(21)]>"
) 

2014-07-04 17:46:28.586 AutoLayoutExample[1110:70b] current constraints ( "<NSIBPrototypingLayoutConstraint:0x8b95fb0 'IB auto generated at build time for view with fixed frame' H:|-(179)-[UILabel:0x8b93e80](LTR) (Names: '|':UIView:0x8b95290 )>", "<NSIBPrototypingLayoutConstraint:0x8b960e0 'IB auto generated at build time for view with fixed frame' H:[UILabel:0x8b93e80(42)]>" ) 2014-07-04 17:46:28.587 AutoLayoutExample[1110:70b] current constraints ( "<NSIBPrototypingLayoutConstraint:0x8b95d60 'IB auto generated at build time for view with fixed frame' V:|-(147)-[UILabel:0x8b93e80] (Names: '|':UIView:0x8b95290 )>", "<NSIBPrototypingLayoutConstraint:0x8b96110 'IB auto generated at build time for view with fixed frame' V:[UILabel:0x8b93e80(21)]>" )

 可以看出IB產生的是IB auto generated at build time for view with fixed frame,無論intrinsic content size如何變化,都無濟於事。所以,在使用AutoLayout時,切記:每個元素都應該有能完全確定size和位置的constraints, 如果有一樣不能確定,IB都會提示Error 或者Warning,而這些Error或者Warning也是必須解決的。

關於兩種PlaceHolder

placeholder constraits 和placeholder instrinsic content size

placeholder constraits是說這個constraint只是個placeholder,在build時就會被去掉,這樣可以阻止IB自動生成constraints;placeholder instrinsic content size是說在IB中設計時使用的size,在runtime時則需要調用intrinsicContentSize方法來確定。

下面說說intrinsicContentSize和constraint的關系:intrinsicContentSize和constraint是Auto Layout的支柱概念,缺一不可。同時有時intrinsicContentSize可以在某個方面也是一種constraint,通常unambiguous layout generally requires setting two attributes in each axis(也就是在一個維度上需要設置起點和長度兩個信息). When a view has an intrinsic content size, that size accounts for one of the two attributes.(如果一個view 有intrinsicContentSize,並且設計者想這樣,intrinsicContentSize是可以起到那個長度的限制作用的) You can, for example, place a text-based control or an image view in the center of its superview, and its layout will not be ambiguous. The intrinsic content size plus the location combine for a fully specified placement. 能夠這樣的前提是1. 使用系統的標准View,2. 在IB中指定Intrinsic size時需要用Default(System defined),比如如果只指定位置信息,不指定size,使用system default intrinsic size,時,輸出時這樣的

2014-07-04 22:25:40.866 AutoLayoutExample[2237:70b] current constraints (
    "<NSLayoutConstraint:0x8a6bde0 H:|-(179)-[UILabel:0x8a6a010]   (Names: '|':UIView:0x8a6b400 )>",
    "<NSContentSizeLayoutConstraint:0x8b847a0 H:[UILabel:0x8a6a010(42)] Hug:251 CompressionResistance:750>"
) 
2014-07-04 22:25:40.868 AutoLayoutExample[2237:70b] current constraints (
    "<NSLayoutConstraint:0x8a6bd30 V:[_UILayoutGuide:0x8a6b4b0]-(127)-[UILabel:0x8a6a010]>",
    "<_UILayoutSupportConstraint:0x8a67660 V:[_UILayoutGuide:0x8a6b4b0(20)]>",
    "<_UILayoutSupportConstraint:0x8a6a300 V:|-(0)-[_UILayoutGuide:0x8a6b4b0]   (Names: '|':UIView:0x8a6b400 )>",
    "<NSContentSizeLayoutConstraint:0x8b847e0 V:[UILabel:0x8a6a010(21)] Hug:251 CompressionResistance:750>"
) 
2014-07-04 22:25:40.869 AutoLayoutExample[2237:70b] current constraints (
    "<NSLayoutConstraint:0x8a6bde0 H:|-(179)-[UILabel:0x8a6a010]   (Names: '|':UIView:0x8a6b400 )>",
    "<NSContentSizeLayoutConstraint:0x8b847a0 H:[UILabel:0x8a6a010(42)] Hug:251 CompressionResistance:750>"
) 
2014-07-04 22:25:40.870 AutoLayoutExample[2237:70b] current constraints (
    "<NSLayoutConstraint:0x8a6bd30 V:[_UILayoutGuide:0x8a6b4b0]-(127)-[UILabel:0x8a6a010]>",
    "<_UILayoutSupportConstraint:0x8a67660 V:[_UILayoutGuide:0x8a6b4b0(20)]>",
    "<_UILayoutSupportConstraint:0x8a6a300 V:|-(0)-[_UILayoutGuide:0x8a6b4b0]   (Names: '|':UIView:0x8a6b400 )>",
    "<NSContentSizeLayoutConstraint:0x8b847e0 V:[UILabel:0x8a6a010(21)] Hug:251 CompressionResistance:750>"
) 

 

如果只指定位置信息,但不指定size信息,但intrisic size是PlaceHolder,width 和height 都是None時輸出是這樣的:

2014-07-04 21:11:56.941 AutoLayoutExample[1790:70b] current constraints (
    "<NSLayoutConstraint:0x8ad9670 H:|-(179)-[UILabel:0x8ad7880]   (Names: '|':UIView:0x8ad8c90 )>",
    "<NSIBPrototypingLayoutConstraint:0x8ad9c10 'IB auto generated at build time for view with ambiguity' H:[UILabel:0x8ad7880(42@251)] priority:251>"
) 
2014-07-04 21:11:56.942 AutoLayoutExample[1790:70b] current constraints (
    "<NSLayoutConstraint:0x8ad95c0 V:[_UILayoutGuide:0x8ad8d40]-(127)-[UILabel:0x8ad7880]>",
    "<_UILayoutSupportConstraint:0x8a6d3f0 V:[_UILayoutGuide:0x8ad8d40(20)]>",
    "<_UILayoutSupportConstraint:0x8aaf250 V:|-(0)-[_UILayoutGuide:0x8ad8d40]   (Names: '|':UIView:0x8ad8c90 )>",
    "<NSIBPrototypingLayoutConstraint:0x8ad9c40 'IB auto generated at build time for view with ambiguity' V:[UILabel:0x8ad7880(21@251)] priority:251>"
) 
2014-07-04 21:11:56.943 AutoLayoutExample[1790:70b] current constraints (
    "<NSLayoutConstraint:0x8ad9670 H:|-(179)-[UILabel:0x8ad7880]   (Names: '|':UIView:0x8ad8c90 )>",
    "<NSIBPrototypingLayoutConstraint:0x8ad9c10 'IB auto generated at build time for view with ambiguity' H:[UILabel:0x8ad7880(42@251)] priority:251>"
) 
2014-07-04 21:11:56.944 AutoLayoutExample[1790:70b] current constraints (
    "<NSLayoutConstraint:0x8ad95c0 V:[_UILayoutGuide:0x8ad8d40]-(127)-[UILabel:0x8ad7880]>",
    "<_UILayoutSupportConstraint:0x8a6d3f0 V:[_UILayoutGuide:0x8ad8d40(20)]>",
    "<_UILayoutSupportConstraint:0x8aaf250 V:|-(0)-[_UILayoutGuide:0x8ad8d40]   (Names: '|':UIView:0x8ad8c90 )>",
    "<NSIBPrototypingLayoutConstraint:0x8ad9c40 'IB auto generated at build time for view with ambiguity' V:[UILabel:0x8ad7880(21@251)] priority:251>"
) 

size信息部分是由IB自動生成的,但是它們的priority只有251,而不是之前的1000(required)了。

只指定位置,對比Default 和 PlaceHolder的 constraints,可以看到,在使用Default時,IB給自動加了NSContentSizeLayoutConstraint;在使用Placeholder時,IB自動生成了NSIBPrototypingLayoutConstraint,因為我們使用了PlaceHolder,並且size都是0,所以IB已經無法知道size信息了,為了避免ambiguity就只能自動加了。

我們在使用custom view時,需要指定intrinsic size為placeholder,那我們應該怎么解決IB自動添加ambiguity的constraint的問題呢?

事實上,如果我們的view是個custom view的話,IB是不會自動添加ambity的constraint,IB會添加NSContentSizeLayoutConstraint,然后在runtime時調用custom view 的intrinsicContentSize來知道view應該有多大。

還有繼續說說intrinsicContentSize,事實上它不是一個人在戰斗,其他的constraint只有一個priority,但是intrinsicContentSize有兩個,分別叫Content Hugging Priority和Content Compression Resistancy Priority。 Content Hugging Priority控制當view frame>intrinsicContentSize時,是不是要縮小view 的size;而Content Compression Resistancy Priority控制當view frame<intrinsicContentSize時, 要不要截斷content,保持view frame size。

舉例來說,如果我有個UILabel,開始Title為“Label”,設置Width constraint 為42@500,設置Content Hugging Priority為1000, 設置Content Compression Resistancy Priority為1。如果我在runtime時改動Title為“S”,那整個UILabel的size都被縮小到只能容下5,因為這時frame size大於IntrinsicContentSize,Content Hugging Priority為1000,要比width constraint高,所以應該是Content Hugging 起作用;如果我把Title改為“325ioqukejgakshgkjashdgjka”,那這個UILabel的size會變為42,內容被截斷為“32...”,因為這時frame size比IntrinsicContentSize小,Content Compression Resistancy Priority只有1,width constraint起作用,將寬度設置為42。

 

一個使用AutoLayout的有趣Bug

 

刪除CenterY之前,IB知道X和Y 位置信息,因此系統給加的是ContentSizeLayoutConstraint,但刪除之后,IB無法確定其Y方向的信息,生成了PrototypingLayoutConstraint。但為什么一個只有251的priority的PrototypingLayoutConstraint不會clip label呢?那我們就需要更多的了解PrototypingLayoutConstraint了。

 

//Before
2014-07-05 23:29:40.068 AutoLayoutExample[2035:70b] current constraints (
    "<NSLayoutConstraint:0x8b44c20 H:|-(10)-[UILabel:0x8b450f0]   (Names: '|':UITableViewCellContentView:0x8b453e0 )>",
    "<NSContentSizeLayoutConstraint:0x8b37520 H:[UILabel:0x8b450f0(42)] Hug:251 CompressionResistance:750>"
) 

//After
2014-07-05 23:32:19.251 AutoLayoutExample[2062:70b] current constraints (
    "<NSLayoutConstraint:0x8b66a10 H:|-(10)-[UILabel:0x8b664d0]   (Names: '|':UITableViewCellContentView:0x8b66210 )>",
    "<NSIBPrototypingLayoutConstraint:0x8b521f0 'IB auto generated at build time for view with ambiguity' H:[UILabel:0x8b664d0(42@251)] priority:251>"
) 

 

 

 

 

 

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM