AutoLayout确实非常方便,比起刀耕火种的手写frame要强大很多。体会一下下面的经典例子,就知道了。

旋转后自动布局

autolayout demo

上面的例子可以用下面的代码实现:

    [super viewDidLoad];
    self.view.backgroundColor=[UIColor whiteColor];
    
    UIView *a = [[UIView alloc] init];
    a.backgroundColor = [UIColor redColor];
    a.layer.cornerRadius=4;
    [a setTranslatesAutoresizingMaskIntoConstraints:NO];
    [self.view addSubview:a];
    
    UIView *b = [[UIView alloc] init];
    b.backgroundColor = [UIColor greenColor];
    b.layer.cornerRadius=4;
    [b setTranslatesAutoresizingMaskIntoConstraints:NO];
    [self.view addSubview:b];
    
    UIView *c = [[UIView alloc] init];
    c.backgroundColor = [UIColor blueColor];
    c.layer.cornerRadius=4;
    [c setTranslatesAutoresizingMaskIntoConstraints:NO];
    [self.view addSubview:c];
    
    NSDictionary *views=NSDictionaryOfVariableBindings(a,b,c);
    NSDictionary *metrics=@{@"padding":@10};
    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-padding-[a(==b)]-padding-[b]-padding-|" options:NSLayoutFormatAlignAllTop metrics:metrics views:views]];
    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-padding-[a(==b)]-padding-[c(==b)]-padding-|" options:0 metrics:metrics views:views]];
    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-padding-[c]-padding-|" options:0 metrics:metrics views:views]];
    

自动计算兄弟元素位置

demo2

上面的例子如果用frame是比较麻烦的。因为除了更新自己的height以外,还要更新其他兄弟节点的origin.y。如果用autolayout就很方便:

    self.view.backgroundColor=[UIColor whiteColor];
    //注意self.view并没有self.view.translatesAutoresizingMaskIntoConstraints=NO;
    id lastView=nil;
    for (int i=1; i<=10; i++) {
        UIButton *v=[UIButton new];
        [v setTitle:[NSString stringWithFormat:@"[+] button-%d",i] forState:UIControlStateNormal];
        [v setTitle:[NSString stringWithFormat:@"[-] button-%d",i] forState:UIControlStateSelected];
        v.backgroundColor=[UIColor colorWithWhite:i*25.0/255 alpha:1];

        [self.view addSubview:v];
        v.translatesAutoresizingMaskIntoConstraints=NO;
        
        [self.view addConstraint:[NSLayoutConstraint constraintWithItem:v attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTrailing multiplier:1 constant:-10]];
        [self.view addConstraint:[NSLayoutConstraint constraintWithItem:v attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeLeading multiplier:1 constant:10]];
        [self.view addConstraint:[NSLayoutConstraint constraintWithItem:v attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:(lastView?:self.topLayoutGuide) attribute:NSLayoutAttributeBottom multiplier:1 constant:0]];
        NSLayoutConstraint *height=[NSLayoutConstraint constraintWithItem:v attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:0 constant:43];
        height.identifier=@"myheight";//通过设置identifier,来找到这个NSLayoutConstraint
        [v addConstraint:height];
        lastView=v;
        //"UIControl+Blocks.h" 或者addTarget
        [v addEventHandler:^(id sender) {
            UIButton *btn=sender;
            NSLog(@"%d clicked\n%@",i,btn.constraints);
            for (NSLayoutConstraint *c in btn.constraints) {
                if ([c.identifier isEqualToString:@"myheight"]) {
                    c.constant= (c.constant==100?43:100);
                    btn.selected=c.constant==100;
                }
            }
            [UIView animateWithDuration:.25 animations:^{
                [self.view layoutIfNeeded];
            }];
           
            
        } forControlEvents:UIControlEventTouchUpInside];
    }

Autolayout和UIScrollView

根据官方文档,UIScrollView使用AutoLayout有两种方法。考虑下面的例子:

demo-3

#方法1,纯autolayout,注意边界。

    self.view.backgroundColor=[UIColor whiteColor];
    UIScrollView *sv=[UIScrollView new];
    sv.translatesAutoresizingMaskIntoConstraints=NO;
    [self.view addSubview:sv];
    
    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[sv]|" options:0 metrics: 0 views:NSDictionaryOfVariableBindings(sv)]];
    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[sv]|" options:0 metrics: 0 views:NSDictionaryOfVariableBindings(sv)]];
    UIView *lastView=nil;
    int length=100;
    for (int i=0; i<length; i++) {
        UIButton *btn=[UIButton new];
        btn.backgroundColor=[UIColor colorWithWhite:i*0.01 alpha:1];
        [btn setTitle:[NSString stringWithFormat:@"button-%d",i] forState:UIControlStateNormal];
        btn.translatesAutoresizingMaskIntoConstraints=NO;
        [sv addSubview:btn];
        [sv addConstraint:[NSLayoutConstraint constraintWithItem:btn attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:0 constant:i*4+100]];
        [sv addConstraint:[NSLayoutConstraint constraintWithItem:btn attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:sv attribute:NSLayoutAttributeCenterX multiplier:1 constant:0]];
        if (i==0) {
            [sv addConstraint:[NSLayoutConstraint constraintWithItem:btn attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:sv attribute:NSLayoutAttributeTop multiplier:1 constant:10]];
        }else{
            [sv addConstraint:[NSLayoutConstraint constraintWithItem:btn attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:lastView attribute:NSLayoutAttributeBottom multiplier:1 constant:1]];
        }
        if (i==length-1) {//关键点。非常重要!设置contentsize的height,最大的一个设置width,否则会出错。
            [sv addConstraint:[NSLayoutConstraint constraintWithItem:btn attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:sv attribute:NSLayoutAttributeBottom multiplier:1 constant:-10]];
            [sv addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[btn]|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(btn)]];
        }
        lastView=btn;

#方法2,使用中间view,利用systemLayoutSizeFittingSize设置contentsize

    self.automaticallyAdjustsScrollViewInsets=NO;
    self.view.backgroundColor=[UIColor whiteColor];
    UIScrollView *sv=[[UIScrollView alloc]initWithFrame:CGRectMake(0, MARGIN_TOP, SCREEN_WIDTH, CONTENT_HEIGHT)];
    [self.view addSubview:sv];
    
    UIView *view=[UIView new];
    view.translatesAutoresizingMaskIntoConstraints=NO;//都添加到view上面。
    [sv addSubview:view];
    
    UIView *lastView=nil;
    int length=100;
    for (int i=0; i<length; i++) {
        UIButton *btn=[UIButton new];
        btn.backgroundColor=[UIColor colorWithWhite:i*0.01 alpha:1];
        [btn setTitle:[NSString stringWithFormat:@"button-%d",i] forState:UIControlStateNormal];
        btn.translatesAutoresizingMaskIntoConstraints=NO;
        [view addSubview:btn];
        [view addConstraint:[NSLayoutConstraint constraintWithItem:btn attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:0 constant:i*4+100]];
        [view addConstraint:[NSLayoutConstraint constraintWithItem:btn attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:view attribute:NSLayoutAttributeCenterX multiplier:1 constant:0]];
        if (i==0) {
            [view addConstraint:[NSLayoutConstraint constraintWithItem:btn attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:view attribute:NSLayoutAttributeTop multiplier:1 constant:10]];
        }else{
            [view addConstraint:[NSLayoutConstraint constraintWithItem:btn attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:lastView attribute:NSLayoutAttributeBottom multiplier:1 constant:1]];
        }
        if (i==length-1) {//关键点。非常重要!设置contentsize的height,最大的一个设置width,否则会出错。
            [view addConstraint:[NSLayoutConstraint constraintWithItem:btn attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:view attribute:NSLayoutAttributeBottom multiplier:1 constant:-10]];
            [view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[btn]|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(btn)]];
        }
        lastView=btn;
    }
    //关键点。非常重要.设置contentsize以滚动。
    CGSize size=[view systemLayoutSizeFittingSize:UILayoutFittingCompressedSize];
    view.frame=CGRectMake(0, 0, size.width, size.height);
    sv.contentSize=size;