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佈局的視圖都會跟着改變約束。
太累了。這些代碼太繁瑣了。