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布局的视图都会跟着改变约束。

太累了。这些代码太繁琐了。

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