考虑到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 = [[UILabel
alloc]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;
只要能够取到宽高约束,那么重设宽高或是去除都可以。