在代碼中使用Autolayout – intrinsicContentSize和Content Hugging Priority

我們繼續來看在代碼中使用Autolayout的話題。先說intrinsicContentSize,也就是控件的內置大小。比如UILabel,UIButton等控件,他們都有自己的內置大小。控件的內置大小往往是由控件本身的內容所決定的,比如一個UILabel的文字很長,那麼該UILabel的內置大小自然會很長。控件的內置大小可以通過UIView的intrinsicContentSize屬性來獲取內置大小,也可以通過invalidateIntrinsicContentSize方法來在下次UI規劃事件中重新計算intrinsicContentSize。如果直接創建一個原始的UIView對象,顯然它的內置大小爲0。

 

繼續用代碼來寫Autolayout,先寫一個輔助方法來快速設置UIView的邊距限制:

//設置Autolayout中的邊距輔助方法
- (void)setEdge:(UIView*)superview view:(UIView*)view attr:(NSLayoutAttribute)attr constant:(CGFloat)constant
{
[superview addConstraint:[NSLayoutConstraint constraintWithItem:view attribute:attr relatedBy:NSLayoutRelationEqual toItem:superview attribute:attr multiplier:1.0 constant:constant]];
}

 

接下來,創建一個UIView,利用上面的輔助方法快速設置其在父控件的左,上,右邊距爲20單位。如下代碼:

//view1
UIView *view1 = [UIView new];
view1.backgroundColor = [UIColor yellowColor];
//不允許AutoresizingMask轉換成Autolayout
view1.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:view1];
//設置左,上,右邊距爲20.
[self setEdge:self.view view:view1 attr:NSLayoutAttributeLeft constant:20];
[self setEdge:self.view view:view1 attr:NSLayoutAttributeTop constant:20];
[self setEdge:self.view view:view1 attr:NSLayoutAttributeRight constant:-20];

 

但是運行後會發現,界面上不會顯示任何東西。原因就是上面講的,UIView默認是沒有intrinsicContentSize的。我們可以通過創建一個自定義的UIView來改寫intrinsicContentSize。

比如,創建一個新的類型:MyView。

 

然後在.m文件中改寫intrinsicContentSize方法,並返回有效值,比如這樣:

//改寫UIView的intrinsicContentSize
- (CGSize)intrinsicContentSize
{
return CGSizeMake(70, 40);
}

 

接着修改最上面的代碼,把上面view1變量的類型從UIView替換成我們自定義的View:MyView類型:

MyView *view1 = [MyView new];

 

再次運行代碼,View會按照要求顯示在屏幕上:

 

接下來,按照同樣的方式,在下方添加另一個MyView,要求其距離父控件邊距左,下,右各爲20,代碼:

//view2
MyView *view2 = [MyView new];
view2.backgroundColor = [UIColor yellowColor];
//不允許AutoresizingMask轉換成Autolayout
view2.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:view2];
//設置左,下,右邊距爲20.
[self setEdge:self.view view:view2 attr:NSLayoutAttributeLeft constant:20];
[self setEdge:self.view view:view2 attr:NSLayoutAttributeBottom constant:-20];
[self setEdge:self.view view:view2 attr:NSLayoutAttributeRight constant:-20];

運行後是這樣:

 

接下來,通過代碼加入Autolayout中的間距。命令view1和view2上下必須間隔20個單位,注意這裏要求view2在view1之下的20單位,所以創建NSLayoutConstraint中view2參數在前面。同時注意,view2的attribute參數是NSLayoutAttributeTop,而view1的attribute參數是NSLayoutAttributeBottom:

//設置兩個View上下間距爲20
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:view2 attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:view1 attribute:NSLayoutAttributeBottom multiplier:1.0 constant:20]];

 

運行結果:

 

OK,的確,此時view1和view2相互間隔20單位,但是view1被拉伸了。

接下來的任務就是做到如何不讓view1拉伸,而讓view2拉伸呢?這裏就需要使用控件的Content Hugging Priority,這個屬性在Xcode中的控件屬性中很常見,如下圖:

 

Content Hugging Priority代表控件拒絕拉伸的優先級。優先級越高,控件會越不容易被拉伸。

而下面的Content Compression Resistance Priority代表控件拒絕壓縮內置空間的優先級。優先級越高,控件的內置空間會越不容易被壓縮。而這裏的內置空間,就是上面講的UIView的intrinsicContentSize。

所以,如果我們把view1(上圖中被拉伸的,在上面的View)的Content Hugging Priority設置一個更高的值,那麼當Autolayout遇到這種決定誰來拉伸的情況時,view1不會被優先拉伸,而優先級稍低的view2纔會被拉伸。

 

可以直接通過UIView的setContentHuggingPriority:forAxis方法來設置控件的Content Hugging Priority,其中forAxis參數代表橫向和縱向,本例中只需要設置縱向,所以傳入UILayoutConstraintAxisVertical。整句代碼:

//提高view1的Content Hugging Priority
[view1 setContentHuggingPriority:UILayoutPriorityDefaultHigh forAxis:UILayoutConstraintAxisVertical];

 

運行結果:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章