CHCR讓佈局更婀娜

傳統方式佈局的弊端

兩個label同一行佈局的時候,傳統作法是將其中的一個label的寬度固定;另一個label設置左右約束,讓它跟隨屏幕寬度拉伸壓縮。以下的例子,我給商品數量Label加了一個60寬度約束。而後,咱們先來看看這樣作的問題html

  • 極端狀況,當商品數量很大時就顯示不下了。

image

  • 商品名稱很長時,商品數量的剩餘寬度顯得有些浪費空間(浪費的程度要看具體的商品數量最大與最小的差值)

image

如何解決

要解決這兩個問題就須要讓兩個Label的寬度在必定程度上自動調整。那這個調整究竟是怎樣一個程度呢?bash

首先,確定跟業務有關。在兩個文本的寬度與間距之和大於屏幕的時候至少是有一個沒法徹底顯示的。通常狀況下不會讓兩個文本都顯示不全(這樣也太秀了),那麼如何作取捨就看業務了。在本文的例子中,商品名稱與數量,確定是要先保證數量能夠看獲得。app

在兩個文本寬度與間距之和小於屏幕的時候,毫無懸念,就是兩個文本都顯示。都顯示的時候,是拉伸其中一個Label仍是不拉伸任何Label?這個不重要,重要的是加約束方便就好。ide

把商品數量Label的寬度去掉就出現了一個錯誤(注意此時整體寬度不足屏幕寬度),由於此時系統不知道如何拉伸或者壓縮以知足總體約束。佈局

image

查看約束錯誤的快捷修復信息,大概意思是把 商品數量Label的 horizontal hugging 從251下降到250以達到比其它View低的目的。ui

image

那麼 horizontal hugging 又是什麼鬼?咱們回頭看一下AutoLayout文檔基礎的東西this

[AutoLayout Guide:Anatomy of a Constraint](developer.apple.com/library/arc…)atom

用到的基礎知識

在 Intrinsic Content Size 這一節有這樣一張圖:spa

image

Content huggingContent compression Resistance 簡稱爲CHCR設計

對應的解釋比較冗長,直接看等價的約束來的實在點

// 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
複製代碼

在每個視圖中這兩種約束時同時存在的,爲了不衝突,AutoLayout設計者給了一個默認的 優先級。By default, views use a 250 priority for their content hugging, and a 750 priority for their compression resistance. 這個默認值在Interface Builder 的 size inspector 中能看獲得。

Constaints
Compression Resistance Priority 高於 Content Hugging Priority 就致使了一個控件更容易被拉伸而不是被壓縮。由於壓縮可能致使顯示不全,因此更容易拉伸是比較合理的。

瞭解完這兩個屬性,咱們回頭看一下這個錯誤。應該就是商品名稱和商品數量兩個Label的Compression Resistance PriorityContent Hugging 都相同,AutoLayout 不知道拉伸或者壓縮哪個Label形成的。

那麼,爲什麼Interface Builder提示咱們修改Content Hugging而不是Compression Resistance Priority呢?文檔中沒有找到相關的說明與解釋。不過我試了一下,當文字長度與間距之和超過屏幕寬度的時候,Interface Builder的提示就變成了修改Compression Resistance Priority。那麼對應的狀況下生效的是哪個屬性,你們用腳趾頭想一下就知道了。

結論

最後咱們回到需求:商品數量維持所有顯示,商品名稱最大化顯示。 結論就是把商品數量Label的Compression Resistance PriorityContent Hugging 都設置成比商品名稱高。效果如圖:

效果

本文以橫向的兩個Label爲例,縱向、多個或者過個其它有內容不定寬高的控件均可以經過這樣的方式去作約束。具體如何,就留給你們本身推導。

補充一個意外狀況,這樣的狀況能夠給商品數量加一個寬度上限。

意外狀況

####完了? ###代碼呢? ##代碼呢? #代碼呢?

Show the code

有一句話是怎麼說的: nib能實現的,代碼都能實現 若是不是,儘管過來找我。 我~

求教

代碼實現也很簡單,UIView的幾個方法

- (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);
複製代碼

以及參數對應的兩個枚舉

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. 複製代碼
相關文章
相關標籤/搜索