iOS: 在代碼中使用Autolayout

原理:IOS6.0 以後,蘋果優化了UI界面的佈局方式,提出了自動佈局的概念,和以前的autoresizing相比功能更強大。子視圖基於父視圖的自動佈局顯示。都是父視圖去添加對子視圖的約束。git

在這裏主要說的是經過代碼對自動佈局視圖的實現。github

代碼中通常用到的有兩個添加約束的方式:ide

1.- (void)addConstraint:(NSLayoutConstraint *)constraint NS_AVAILABLE_IOS(6_0);函數

2.- (void)addConstraints:(NSArray *)constraints NS_AVAILABLE_IOS(6_0);佈局

<優化

在使用自動佈局以前要對子視圖的佈局方式進行調整,用到這個UIView的屬性。動畫

- (BOOL)translatesAutoresizingMaskIntoConstraints NS_AVAILABLE_IOS(6_0); // Default YESui

須要將其設置爲NO;spa

>code

下面用簡單例子說明一下:

(1) – 按比例縮放和優先級

首先說按比例縮放,這是在Interface Builder中沒法設置的內容。而在代碼中,使用NSLayoutConstraint類型的初始化函數中的multiplier參數就能夠很是簡單的設置按比例縮放。同時也能夠設置不一樣NSLayoutAttribute參數來達到意想不到的效果,好比「A的Width等於B的Height的2倍」這樣的效果。

 1    topLabel= [[UILabel alloc] initWithFrame:CGRectZero];
 2     topLabel.translatesAutoresizingMaskIntoConstraints = NO;
 3     topLabel.backgroundColor = [UIColor lightGrayColor];
 4     topLabel.numberOfLines = 0;
 5     topLabel.text = @"選我選我選我選我選我選我";
 6     topLabel.userInteractionEnabled = YES;
 7     UITapGestureRecognizer *tt = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(nextContro)];
 8     [topLabel addGestureRecognizer:tt];
 9     [self.view addSubview:topLabel];
10     
11     secondLabel = [[UILabel alloc] initWithFrame:CGRectZero];
12     secondLabel.translatesAutoresizingMaskIntoConstraints = NO;
13     secondLabel.backgroundColor = [UIColor cyanColor];
14     secondLabel.text = @"按我";
15     secondLabel.userInteractionEnabled = YES;
16     UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(changeThirdLabel:)];
17     [secondLabel addGestureRecognizer:tap];
18     [self.view addSubview:secondLabel];
19     
20     thirdLabel = [[UILabel alloc] initWithFrame:CGRectZero];
21     thirdLabel.translatesAutoresizingMaskIntoConstraints = NO;
22     thirdLabel.backgroundColor = [UIColor purpleColor];
23     thirdLabel.numberOfLines = 0;
24     thirdLabel.text = str;
25     [self.view addSubview:thirdLabel];

設置firstLabel的佈局

1 NSLayoutConstraint *widthConstraint = [NSLayoutConstraint constraintWithItem:topLabel attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeWidth multiplier:1 constant:0];
2     NSLayoutConstraint *heightConstraint = [NSLayoutConstraint constraintWithItem:topLabel attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeHeight multiplier:0.2 constant:0];
3     
4     [self.view addConstraint:widthConstraint];
5     [self.view addConstraint:heightConstraint];

設置secondLabel的位置

1 //設置view之間長度相等,而且在試圖在邊緣內(超過邊緣自動往下)
2     [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[topLabel][secondLabel(==topLabel)]|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(topLabel, secondLabel)]];
3     
4     //設置高度,距頂部20,之間間隔10,secondLabel高度爲30,只是上面對齊下面不對齊
5     [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-20-[topLabel(>=20@400)]-10-[secondLabel(==30)]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(topLabel, secondLabel)]];

注:這裏無論是在format字符串裏仍是在binding字典裏,不能使用self.label這樣的字樣

設置thirdLabel的位置並根據文本動態顯示高度

 1  //水平居中,始終距離父View底部20單位的距離。而後高度是父View高度的5分之一
 2     //居中
 3     [self.view addConstraint:[NSLayoutConstraint constraintWithItem:thirdLabel attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterX multiplier:1 constant:0]];
 4      //距離底部50,注意NSLayoutConstraint建立的constant是加在toItem參數的,因此須要-20。
 5     [self.view addConstraint:[NSLayoutConstraint constraintWithItem:thirdLabel attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeBottom multiplier:1 constant:-50]];
 6     //定義高度是父View的5分之一
 7 //    [self.view addConstraint:[NSLayoutConstraint constraintWithItem:thirdLabel attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeHeight multiplier:0.5 constant:0]];
 8     
 9     NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:thirdLabel attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeWidth multiplier:1 constant:0];
10     constraint.priority = UILayoutPriorityDefaultHigh;
11     [self.view addConstraint:constraint];
12     //最小高度爲150
13     [thirdLabel addConstraint:[NSLayoutConstraint constraintWithItem:thirdLabel attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationGreaterThanOrEqual toItem:nil attribute:NSLayoutAttributeHeight multiplier:1 constant:150]];
14     
15     //註冊KVO方法
16     [thirdLabel addObserver:self forKeyPath:@"bounds" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionInitial context:nil];
//KVO回掉
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    if (object == thirdLabel && [keyPath isEqualToString:@"bounds"]) {
//        thirdLabel.text = str;
//        thirdLabel.text = @"ha";
//        thirdLabel.text = NSStringFromCGSize(thirdLabel.bounds.size);
    }
}

能夠設置空間展現的動畫效果

 

 [UIView animateWithDuration:0.5 animations:^{
        [self.view layoutIfNeeded];
    }];

 

 

 

(2) – intrinsicContentSize和Content Hugging Priority

先說intrinsicContentSize,也就是控件的內置大小。好比UILabel,UIButton等控件,他們都有本身的內置大小。控件的內置大小每每是由控件自己的內容所決定的,好比一個UILabel的文字很長,那麼該UILabel的內置大小天然會很長。控件的內置大小能夠經過UIView的intrinsicContentSize屬性來獲取內置大小,也能夠經過invalidateIntrinsicContentSize方法來在下次UI規劃事件中從新計算intrinsicContentSize。若是直接建立一個原始的UIView對象,顯然它的內置大小爲0。

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

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

接下來,建立一個UIView,利用上面的輔助方法快速設置其在父控件的左,上,右邊距爲20單位。UIView默認是沒有intrinsicContentSize的。咱們能夠經過建立一個自定義的UIView來改寫intrinsicContentSize。

在MyView裏添加:

- (CGSize)intrinsicContentSize {
    return CGSizeMake(0, 100); //controll設置了left以及right,故這裏的width沒效果
}

 

以下代碼:

 1  //view1
 2     MyView *view1 = [[MyView alloc] init];
 3     view1.backgroundColor = [UIColor yellowColor];
 4     //不容許AutoresizingMask轉換成Autolayout
 5     view1.translatesAutoresizingMaskIntoConstraints = NO;
 6     [self.view addSubview:view1];
 7     //設置左,上,右邊距爲20.
 8     [self setEdge:self.view view:view1 attr:NSLayoutAttributeLeft constant:20];
 9     [self setEdge:self.view view:view1 attr:NSLayoutAttributeTop constant:80];
10     [self setEdge:self.view view:view1 attr:NSLayoutAttributeRight constant:-20];
11     
12     
13     //view2
14     MyView *view2 = [MyView new];
15     view2.backgroundColor = [UIColor greenColor];
16     //不容許AutoresizingMask轉換成Autolayout
17     view2.translatesAutoresizingMaskIntoConstraints = NO;
18     [self.view addSubview:view2];
19     //設置左,下,右邊距爲20.
20     [self setEdge:self.view view:view2 attr:NSLayoutAttributeLeft constant:20];
21     [self setEdge:self.view view:view2 attr:NSLayoutAttributeBottom constant:-80];
22     [self setEdge:self.view view:view2 attr:NSLayoutAttributeRight constant:-20];
1 //設置兩個View上下間距爲20
2     [self.view addConstraint:[NSLayoutConstraint constraintWithItem:view2 attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:view1 attribute:NSLayoutAttributeBottom multiplier:1.0 constant:20]];

設置view的Content Hugging Priority.Content Hugging Priority表明控件拒絕拉伸的優先級。優先級越高,控件會越不容易被拉伸。

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

能夠直接經過UIView的setContentHuggingPriority:forAxis方法來設置控件的Content Hugging Priority,其中forAxis參數表明橫向和縱向,本例中只須要設置縱向,因此傳入UILayoutConstraintAxisVertical。整句代碼:

[view2 setContentHuggingPriority:UILayoutPriorityDefaultHigh forAxis:UILayoutConstraintAxisVertical];

 

關於constraintsWithVisualFormat:函數介紹:

 constraintsWithVisualFormat:參數爲NSString型,指定Contsraint的屬性,是垂直方向的限定仍是水平方向的限定,參數定義通常以下:

V:|-(>=XXX) :表示垂直方向上相對於SuperView大於、等於、小於某個距離

如果要定義水平方向,則將V:改爲H:便可

在接着後面-[]中括號裏面對當前的View/控件 的高度/寬度進行設定;

options:字典類型的值;這裏的值通常在系統定義的一個enum裏面選取

metrics:nil;通常爲nil ,參數類型爲NSDictionary,從外部傳入 //衡量標準

views:就是上面所加入到NSDictionary中的綁定的View

在這裏要注意的是 AddConstraints  和 AddConstraint 之間的區別,一個添加的參數是NSArray,一個是NSLayoutConstraint

 

使用規則

|: 表示父視圖

  -:表示距離

  V:  :表示垂直

  H:  :表示水平

>= :表示視圖間距、寬度和高度必須大於或等於某個值

    <= :表示視圖間距、寬度和高度必須小宇或等於某個值

    == :表示視圖間距、寬度或者高度必須等於某個值

@  :>=、<=、==  限制   最大爲  1000

 

1.|-[view]-|:  視圖處在父視圖的左右邊緣內

2.|-[view]  :   視圖處在父視圖的左邊緣

3.|[view]   :   視圖和父視圖左邊對齊

4.-[view]-  :  設置視圖的寬度高度

5.|-30.0-[view]-30.0-|:  表示離父視圖 左右間距  30

6.[view(200.0)] : 表示視圖寬度爲 200.0

7.|-[view(view1)]-[view1]-| :表示視圖寬度同樣,而且在父視圖左右邊緣內

8. V:|-[view(50.0)] : 視圖高度爲  50

9: V:|-(==padding)-[imageView]->=0-[button]-(==padding)-| : 表示離父視圖的距離

爲Padding,這兩個視圖間距必須大於或等於0而且距離底部父視圖爲 padding。

10:  [wideView(>=60@700)]  :視圖的寬度爲至少爲60 不能超過  700

11: 若是沒有聲明方向默認爲  水平  V:

 

Demo地址:https://github.com/LiDechao/AutoLayout

相關文章
相關標籤/搜索