AutoLayout是从IOS 6开始苹果引入来取代autoresizing的新的布局技术。使用NSLayoutConstraint对view进行布局,就不需要计算view的frame。引入该约束API是为了更好的做一些屏幕适配的工作。
在使用NSLayoutConstraint之前需要知道以下两点:
- 必须设置 translatesAutoresizingMaskIntoConstraints为NO。
- 如果是viewControl则AutoLayout适配写在[- updateViewConstraints]中;如果是view则AutoLayout适配写在[- updateConstraints]中。
- 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的改变呢?
- 要平移某个控件
- 对某个控件进行缩放
平移:找到对应的约束条件,去改变它的常量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布局的视图都会跟着改变约束。
太累了。这些代码太繁琐了。