iOS開發之NSLayoutConstraint

AutoLayout是從IOS 6開始蘋果引入來取代autoresizing的新的佈局技術。使用NSLayoutConstraint對view進行佈局,就不需要計算view的frame。引入該約束API是爲了更好的做一些屏幕適配的工作。

在使用NSLayoutConstraint之前需要知道以下兩點:

  1. 必須設置 translatesAutoresizingMaskIntoConstraints爲NO。
  2. 如果是viewControl則AutoLayout適配寫在[- updateViewConstraints]中;如果是view則AutoLayout適配寫在[- updateConstraints]中。
  3. NSLayoutConstraint是將約束添加到父控件中。

下面來簡單的使用NSLayoutConstraint。首先創建兩個view(redView, blueView)

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    // 紅色view
    UIView *redView = [[UIView alloc] init];
    redView.backgroundColor = [UIColor redColor];
    [self.view addSubview:redView];
    self.redView = redView;
    // 首先禁用UIViewAutoresizing
    self.redView.translatesAutoresizingMaskIntoConstraints = NO;
    
    
    // 藍色view
    UIView *blueView = [[UIView alloc] init];
    blueView.backgroundColor = [UIColor blueColor];
    [self.view addSubview:blueView];
    self.blueView = blueView;
    // 首先禁用UIViewAutoresizing
    self.blueView.translatesAutoresizingMaskIntoConstraints = NO;

}

下面只對redView相對於父控件self.view進行佈局,確定redView的位置和尺寸方法很多,這裏只是其中一種。

/**
 *  redView相對於父控件佈局
 */
- (void)testConstraint1 {
    
    // 開始對redView進行佈局:NSLayoutConstraint
    // NSLayoutConstraint使用公式:item.attribute = item.attribute * multi + constant
    // redView的頂部約束
    NSLayoutConstraint *topConstraint = [NSLayoutConstraint constraintWithItem:self.view
                                                                     attribute:NSLayoutAttributeTop
                                                                     relatedBy:NSLayoutRelationEqual
                                                                        toItem:self.redView
                                                                     attribute:NSLayoutAttributeTop
                                                                    multiplier:1.0
                                                                      constant:-10];
    
    // redView的左部約束
    NSLayoutConstraint *leftConstraint = [NSLayoutConstraint constraintWithItem:self.view
                                                                      attribute:NSLayoutAttributeLeft
                                                                      relatedBy:NSLayoutRelationEqual
                                                                         toItem:self.redView
                                                                      attribute:NSLayoutAttributeLeft
                                                                     multiplier:1.0
                                                                       constant:-10];
    
    // redView的高度約束
    NSLayoutConstraint *heightConstraint = [NSLayoutConstraint constraintWithItem:self.view
                                                                        attribute:NSLayoutAttributeHeight
                                                                        relatedBy:NSLayoutRelationEqual
                                                                           toItem:self.redView
                                                                        attribute:NSLayoutAttributeHeight
                                                                       multiplier:1.0
                                                                         constant:100];
    
    // redView的右部約束
    NSLayoutConstraint *rightConstraint = [NSLayoutConstraint constraintWithItem:self.view
                                                                       attribute:NSLayoutAttributeRight
                                                                       relatedBy:NSLayoutRelationEqual
                                                                          toItem:self.redView
                                                                       attribute:NSLayoutAttributeRight
                                                                      multiplier:1.0
                                                                        constant:10];
    
    
    // 設置redView的約束
    [self.view addConstraints:@[topConstraint, leftConstraint, heightConstraint, rightConstraint]];
}

橫豎屏效果:


上面介紹的是子控件相對於父控件的佈局,下面介紹兩個子控件之間的相對約束,並設置redView高度約束的優先級。

/**
 *  blueView相對於redView進行佈局
 */

- (void)testConstraint2 {
    
    // 開始對redView進行佈局:NSLayoutConstraint
    // NSLayoutConstraint使用公式:item.attribute = item.attribute * multi + constant
    // redView的頂部約束
    NSLayoutConstraint *topConstraint = [NSLayoutConstraint constraintWithItem:self.redView
                                                                     attribute:NSLayoutAttributeTop
                                                                     relatedBy:NSLayoutRelationEqual
                                                                        toItem:self.view
                                                                     attribute:NSLayoutAttributeTop
                                                                    multiplier:1.0
                                                                      constant:50];
    
    // redView的左部約束
    NSLayoutConstraint *leftConstraint = [NSLayoutConstraint constraintWithItem:self.redView
                                                                      attribute:NSLayoutAttributeLeft
                                                                      relatedBy:NSLayoutRelationEqual
                                                                         toItem:self.view
                                                                      attribute:NSLayoutAttributeLeft
                                                                     multiplier:1.0
                                                                       constant:50];
    
    // redView的寬度約束
    NSLayoutConstraint *widthConstraint = [NSLayoutConstraint constraintWithItem:self.redView
                                                                       attribute:NSLayoutAttributeWidth
                                                                       relatedBy:NSLayoutRelationEqual
                                                                          toItem:self.view
                                                                       attribute:NSLayoutAttributeWidth
                                                                      multiplier:1.0
                                                                        constant:-100];
    
    // 設置高度最小200約束
    NSLayoutConstraint *lessH = [NSLayoutConstraint constraintWithItem:self.redView
                                                             attribute:NSLayoutAttributeHeight
                                                             relatedBy:NSLayoutRelationGreaterThanOrEqual
                                                                toItem:nil
                                                             attribute:NSLayoutAttributeNotAnAttribute
                                                            multiplier:1.0
                                                              constant:200];
    
    
    // 設置高度優先級
    lessH.priority = UILayoutPriorityDefaultHigh;
    
    
    // 設置redView的約束
    [self.view addConstraints:@[topConstraint, leftConstraint, widthConstraint, lessH]];
    
    
    // 開始對blueView進行佈局:NSLayoutConstraint
    // NSLayoutConstraint使用公式:item.attribute = item.attribute * multi + constant
    // blueView的頂部約束
    NSLayoutConstraint *bTopConstraint = [NSLayoutConstraint constraintWithItem:self.blueView
                                                                      attribute:NSLayoutAttributeTop
                                                                      relatedBy:NSLayoutRelationEqual
                                                                         toItem:self.redView
                                                                      attribute:NSLayoutAttributeBottom
                                                                     multiplier:1.0
                                                                       constant:50];
    
    // blueView的左部約束
    NSLayoutConstraint *bLeftConstraint = [NSLayoutConstraint constraintWithItem:self.blueView
                                                                       attribute:NSLayoutAttributeLeft
                                                                       relatedBy:NSLayoutRelationEqual
                                                                          toItem:self.redView
                                                                       attribute:NSLayoutAttributeLeft
                                                                      multiplier:1.0
                                                                        constant:0];
    
    // blueView的寬度約束
    NSLayoutConstraint *bWidthConstraint = [NSLayoutConstraint constraintWithItem:self.blueView
                                                                        attribute:NSLayoutAttributeWidth
                                                                        relatedBy:NSLayoutRelationEqual
                                                                           toItem:self.redView
                                                                        attribute:NSLayoutAttributeWidth
                                                                       multiplier:1.0
                                                                         constant:0];
    
    // blueView的高度約束
    NSLayoutConstraint *bHeightConstraint = [NSLayoutConstraint constraintWithItem:self.blueView
                                                                         attribute:NSLayoutAttributeHeight
                                                                         relatedBy:NSLayoutRelationEqual
                                                                            toItem:nil
                                                                         attribute:NSLayoutAttributeNotAnAttribute
                                                                        multiplier:0.0
                                                                          constant:100];
    
    
    // 設置blueView的約束
    [self.view addConstraints:@[bTopConstraint, bLeftConstraint, bWidthConstraint, bHeightConstraint]];
}

橫豎屏效果:


使用NSLayoutConstraint對控件佈局減少了計算frame的麻煩,不過從上面的代碼可以看出來,要對一個控件進行簡單的約束代碼量還是很大的,不過這也是沒有辦法。

我們如何在NSLayoutConstraint佈局中設置控件的動畫和frame的改變呢?

  1. 要平移某個控件
  2. 對某個控件進行縮放

平移:找到對應的約束條件,去改變它的常量constant,如下點擊控制器view將redView向下平移

/**
 *  查找一個試圖中制定的約束contraint
 *
 *  @param view     被查找的試圖
 *  @param constant 常量
 */
- (void)replaceView:(UIView *)view topConstraintWithConstant:(CGFloat)constant
{
    // 遍歷view上的所有約束
    for (NSLayoutConstraint *constraint in view.superview.constraints) {
        
        // 符合條件的約束
        if (constraint.firstItem == view
            && constraint.firstAttribute == NSLayoutAttributeTop
            ) {
            
            // 執行動畫
            [UIView animateWithDuration:2.0 animations:^{
                
                constraint.constant += constant;
                [self.view layoutIfNeeded];// 重新佈局
            }];
        }
    }
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    
    // 平移
    [self replaceView:self.redView topConstraintWithConstant:200];
    
}
縮放:找到對應的約束條件,移除該約束條件,再添加一個新的約束條件

- (void)performAnimatView:(UIView *)view {
    // 遍歷view上的所有約束
    for (NSLayoutConstraint *constraint in view.superview.constraints) {
        
        // 符合條件的約束
        if (constraint.firstItem == view
            && constraint.firstAttribute == NSLayoutAttributeWidth
            ) {
            
            // 移除該約束條件
            [self.view removeConstraint:constraint];
            
            
            // 添加新的約束條件,並執行動畫
            [UIView animateWithDuration:2.0 animations:^{
                
                NSLayoutConstraint *cw = [NSLayoutConstraint constraintWithItem:self.redView
                                                                      attribute:NSLayoutAttributeWidth
                                                                      relatedBy:NSLayoutRelationEqual
                                                                         toItem:self.view
                                                                      attribute:NSLayoutAttributeWidth
                                                                     multiplier:1.0
                                                                       constant:-200];
                [self.view addConstraint:cw];
                
                [self.view layoutIfNeeded];// 重新佈局
            }];
        }
    }

}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    
    // 縮放
    [self performAnimatView:self.redView];
    
}

注意:當修改一個view的約束的時候,其他相對於該view佈局的視圖都會跟着改變約束。

太累了。這些代碼太繁瑣了。

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