傳統(tǒng)方式布局的弊端
兩個(gè)label同一行布局的時(shí)候,傳統(tǒng)做法是將其中的一個(gè)label的寬度固定;另外一個(gè)label設(shè)置左右約束,讓它跟隨屏幕寬度拉伸壓縮。如下的例子,我給商品數(shù)量Label加了一個(gè)60寬度約束。然后,我們先來看看這樣做的問題
- 極端情況,當(dāng)商品數(shù)量很大時(shí)就顯示不下了。
- 商品名稱很長時(shí),商品數(shù)量的剩余寬度顯得有些浪費(fèi)空間(浪費(fèi)的程度要看具體的商品數(shù)量最大與最小的差值)
如何解決
要解決這兩個(gè)問題就需要讓兩個(gè)Label的寬度在一定程度上自動(dòng)調(diào)整。那這個(gè)調(diào)整到底是怎樣一個(gè)程度呢?
首先,肯定跟業(yè)務(wù)有關(guān)。在兩個(gè)文本的寬度與間距之和大于屏幕的時(shí)候至少是有一個(gè)無法完全顯示的。一般情況下不會(huì)讓兩個(gè)文本都顯示不全(這樣也太秀了),那么如何做取舍就看業(yè)務(wù)了。在本文的例子中,商品名稱與數(shù)量,肯定是要先保證數(shù)量可以看得到。
在兩個(gè)文本寬度與間距之和小于屏幕的時(shí)候,毫無懸念,就是兩個(gè)文本都顯示。都顯示的時(shí)候,是拉伸其中一個(gè)Label還是不拉伸任何Label?這個(gè)不重要,重要的是加約束方便就好。
把商品數(shù)量Label的寬度去掉就出現(xiàn)了一個(gè)錯(cuò)誤(注意此時(shí)總體寬度不足屏幕寬度),因?yàn)榇藭r(shí)系統(tǒng)不知道如何拉伸或者壓縮以滿足整體約束。
查看約束錯(cuò)誤的快捷修復(fù)信息,大概意思是把 商品數(shù)量Label的 horizontal hugging 從251降低到250以達(dá)到比其它View低的目的。
那么 horizontal hugging 又是什么鬼?我們回頭看一下AutoLayout文檔基礎(chǔ)的東西
AutoLayout Guide:Anatomy of a Constraint
用到的基礎(chǔ)知識(shí)
在 Intrinsic Content Size 這一節(jié)有這樣一張圖:
Content hugging 和 Content compression Resistance 簡稱為CHCR
對應(yīng)的解釋比較冗長,直接看等價(jià)的約束來的實(shí)在點(diǎn)
// Compression Resistance
View.height >= 0.0 * NotAnAttribute + IntrinsicHeight
View.width >= 0.0 * NotAnAttribute + IntrinsicWidth
// Content Hugging
View.height <= 0.0 * NotAnAttribute + IntrinsicHeight
View.width <= 0.0 * NotAnAttribute + IntrinsicWidth
在每一個(gè)視圖中這兩種約束時(shí)同時(shí)存在的,為了避免沖突,AutoLayout設(shè)計(jì)者給了一個(gè)默認(rèn)的
優(yōu)先級。By default, views use a 250 priority for their content hugging, and a 750 priority for their compression resistance.
這個(gè)默認(rèn)值在Interface Builder 的 size inspector 中能看得到。

Compression Resistance Priority 高于 Content Hugging Priority 就導(dǎo)致了一個(gè)控件更容易被拉伸而不是被壓縮。因?yàn)閴嚎s可能導(dǎo)致顯示不全,所以更容易拉伸是比較合理的。
了解完這兩個(gè)屬性,我們回頭看一下這個(gè)錯(cuò)誤。應(yīng)該就是商品名稱和商品數(shù)量兩個(gè)Label的Compression Resistance Priority 和 Content Hugging 都相同,AutoLayout 不知道拉伸或者壓縮哪一個(gè)Label造成的。
那么,為何Interface Builder提示我們修改Content Hugging而不是Compression Resistance Priority呢?文檔中沒有找到相關(guān)的說明與解釋。不過我試了一下,當(dāng)文字長度與間距之和超過屏幕寬度的時(shí)候,Interface Builder的提示就變成了修改Compression Resistance Priority。那么對應(yīng)的情況下生效的是哪一個(gè)屬性,大家用腳趾頭想一下就知道了。
結(jié)論
最后我們回到需求:商品數(shù)量維持全部顯示,商品名稱最大化顯示。
結(jié)論就是把商品數(shù)量Label的Compression Resistance Priority 和 Content Hugging 都設(shè)置成比商品名稱高。效果如圖:

本文以橫向的兩個(gè)Label為例,縱向、多個(gè)或者過個(gè)其它有內(nèi)容不定寬高的控件都可以通過這樣的方式去做約束。具體如何,就留給大家自己推導(dǎo)。
補(bǔ)充一個(gè)意外情況,怎樣的情況可以給商品數(shù)量加一個(gè)寬度上限。

完了?
代碼呢?
代碼呢?
代碼呢?
Show the code
有一句話是怎么說的:
nib能實(shí)現(xiàn)的,代碼都能實(shí)現(xiàn)
如果不是,盡管過來找我。
我~

代碼實(shí)現(xiàn)也很簡單,UIView的幾個(gè)方法
- (UILayoutPriority)contentHuggingPriorityForAxis:(UILayoutConstraintAxis)axis NS_AVAILABLE_IOS(6_0);
- (void)setContentHuggingPriority:(UILayoutPriority)priority forAxis:(UILayoutConstraintAxis)axis NS_AVAILABLE_IOS(6_0);
- (UILayoutPriority)contentCompressionResistancePriorityForAxis:(UILayoutConstraintAxis)axis NS_AVAILABLE_IOS(6_0);
- (void)setContentCompressionResistancePriority:(UILayoutPriority)priority forAxis:(UILayoutConstraintAxis)axis NS_AVAILABLE_IOS(6_0);
以及參數(shù)對應(yīng)的兩個(gè)枚舉
typedef NS_ENUM(NSInteger, UILayoutConstraintAxis) {
UILayoutConstraintAxisHorizontal = 0,
UILayoutConstraintAxisVertical = 1
};
typedef float UILayoutPriority NS_TYPED_EXTENSIBLE_ENUM;
static const UILayoutPriority UILayoutPriorityRequired NS_AVAILABLE_IOS(6_0) = 1000; // A required constraint. Do not exceed this.
static const UILayoutPriority UILayoutPriorityDefaultHigh NS_AVAILABLE_IOS(6_0) = 750; // This is the priority level with which a button resists compressing its content.
static const UILayoutPriority UILayoutPriorityDefaultLow NS_AVAILABLE_IOS(6_0) = 250; // This is the priority level at which a button hugs its contents horizontally.
static const UILayoutPriority UILayoutPriorityFittingSizeLevel NS_AVAILABLE_IOS(6_0) = 50; // When you send -[UIView systemLayoutSizeFittingSize:], the size fitting most closely to the target size (the argument) is computed. UILayoutPriorityFittingSizeLevel is the priority level with which the view wants to conform to the target size in that computation. It's quite low. It is generally not appropriate to make a constraint at exactly this priority. You want to be higher or lower.