首页 > 代码库 > 全面使用自动布局(AutoLayout )的开始

全面使用自动布局(AutoLayout )的开始

    考虑到6和6+进入使用造成的“破坏”,自动布局这个武器“是时候表演真正的技术了!”。

   刚在学习使用“约束”的时候,构建一个label准备试一试,在使用到init方法时,想到没必要设置frame,因为frame根本不能写死,但是我又想这个label有固定的大小,那怎么办呢?那就只用init方法构建,然后设置bounds,虽然可以,但是觉得浪费,而且这样设置的宽高没有添加“约束”,这样的宽高是不稳定的,会被改变的。

   如果全面使用自动布局,直接设置宽高的方式已经不适合了,因为view的宽高是通过约束计算出来的,那么干嘛不直接在view构建的时候添加宽高约束呢?

  所以我通过category给UIView添加了一种init方法:

-(id)initWithConstraintsSize:(CGSize)size{
    
    /*这里不采用super,因为这里是使用category添加方法不是继承UIView,使用super,那么调用的init方法就不是UIView的了。那么UIView构建时的一些系统内部处理就无法做,甚至init出来的可能缺少很多UIVew必须的元素。而使用【self init】,这样就使用了系统的UIView构建方法,所有必须的操作都不会被遗漏。
     */
    
    if (self = [self  init]) {
        
        NSLayoutConstraint* widthConstraint = [NSLayoutConstraint constraintWithItem:self attribute:(NSLayoutAttributeWidth) relatedBy:(NSLayoutRelationEqual) toItem:nil attribute:(NSLayoutAttributeNotAnAttribute) multiplier:1.0 constant:size.width];
        NSLayoutConstraint* heightConstraint = [NSLayoutConstraint constraintWithItem:self attribute:(NSLayoutAttributeHeight) relatedBy:(NSLayoutRelationEqual) toItem:nil attribute:(NSLayoutAttributeNotAnAttribute) multiplier:1.0 constant:size.height];
        
        [self addConstraints:@[widthConstraint,heightConstraint]];
    }
    return self;
}

使用时只需要导入这个category,然后这样构建:

 self.blueLabel = [[UILabelalloc]initWithConstraintsSize:CGSizeMake(200,250)];

这样这个label的宽高打死都不会改变了,不管你之后给它添加了什么其他的约束。


   首先,我思考的问题是,在使用自动布局的环境里,再通过设置frame来设置view的大小可能没有作用,而且很被动。使用自动布局,首先就要转变思维习惯,大小不再是直接设定,而是通过约束计算出来。那么就有两种情况:

1、这个view我需要它和左边的XX保持m宽度,同时和右边的XXX保持n宽度,这样我的宽度就可以被计算出来;这种情况下这个view的宽是可变的,所以不需要设置frame。当然也不适用我上面的方法构建。

2、这个view的宽高时固定或阶段性固定的,这时就需要设置宽高,但是使用设置frame可能会没用,所以使用高宽的约束,但是我太懒了,觉得写起来麻烦,不如直接把添加宽高约束写到init方法里面,使用这个init方法构建出来的view就自带了宽、高约束,这样轻松多了!

 这个简单的方法要这么仔细的说明,是我觉得这是一个开始,全面使用自动布局的开始,因为这样就可以完全抛弃掉使用frame来确定view的位置、大小的旧思路了。


当然还有一些问题:

1、如果这个view只想限定高(或宽)不变怎么办?

    可以把init方法改为:

-(id)initWithConstraintsSize:(CGSize)size WidthConstraint:(BOOL)isWidth heightConstraint:(BOOL)isHeight{
    if (self = [self  init]) {
        
        NSLayoutConstraint* widthConstraint = [NSLayoutConstraint constraintWithItem:self attribute:(NSLayoutAttributeWidth) relatedBy:(NSLayoutRelationEqual) toItem:nil attribute:(NSLayoutAttributeNotAnAttribute) multiplier:1.0 constant:size.width];
        
        NSLayoutConstraint* heightConstraint = [NSLayoutConstraint constraintWithItem:self attribute:(NSLayoutAttributeHeight) relatedBy:(NSLayoutRelationEqual) toItem:nil attribute:(NSLayoutAttributeNotAnAttribute) multiplier:1.0 constant:size.height];
        
        if (isWidth) {
            [self addConstraint:widthConstraint];
        }
        
        if (isHeight) {
            [self addConstraint:heightConstraint];
        }
    }
    return self;
}

通过两个BOOL参数判断是否添加宽、高约束;

2、如果某个时候我想修改这个view的宽怎么办?

首先必须是通过修改宽约束,不是使用这是width,那么就必须取到宽约束,还好有方法取得自身的Constraint。可以在category里再加两个方法:

//获取宽约束
-(NSLayoutConstraint*)getWidthConstaint;

//获取高约束
-(NSLayoutConstraint*)getHeightConstant;
实现:

-(NSLayoutConstraint*)getWidthConstaint{
    
    NSPredicate* predicate = [NSPredicate predicateWithFormat:@"identifier = %@",WConstraintID];
    NSLayoutConstraint* constraint =  [[self.constraints filteredArrayUsingPredicate:predicate] objectAtIndex:0];
    return constraint;
}

-(NSLayoutConstraint*)getHeightConstant{
    NSPredicate* predicate = [NSPredicate predicateWithFormat:@"identifier = %@",HConstainttID];
    NSLayoutConstraint* constraint =  [[self.constraints filteredArrayUsingPredicate:predicate] objectAtIndex:0];
    return constraint;
}

WConstraintID 和   HConstainttID 为两个宏,标记两个”约束“的id,并且在之前的inti方法里需要把这宽高约束的identifier设置好:

widthConstraint.identifier = WConstraintID;

heightConstraint.identifier = HConstainttID;

只要能够取到宽高约束,那么重设宽高或是去除都可以。


全面使用自动布局(AutoLayout )的开始