xib 不是全能的,有的时候不能使用 xib 进行 UI 布局的时候,还是得使用代码布局。
代码布局有两个点要注意:
1. 布局计算
如果是计算frame等,那么要注意这个计算 只进行一次,因此在viewDidLoad做的计算不一定是正确的值,即使是正确的值,也无济于事,因为计算一次这一点意味着计算 frame 无法适配屏幕旋转的情形。
更稳妥的frame计算是放在viewDidLayoutSubviews
等方法里,这是会调用多次的方法,每当UI变更的时候就可以在这里更新计算值,eg:
override func viewDidLayoutSubviews() {
spin.center = CGPoint(x: loginButton.bounds.width / 2, y: loginButton.bounds.height / 2)
}
2. 使用Constraints
更有效的方法当然是使用约束布局法。
这就必须提到一个提高约束编写效率的库 Masonry,这个库已经适配了iPhone X,可以说节省了非常多的编码时间。
在实际使用的时候有两个非常有用的方法:
- (void)didMoveToSuperview
调用两次,一次是视图被添加到父视图的时候,第二次则是视图被移出父视图的时候,因此我们可以在这里添加一些相对父视图的约束,eg:
- (void)didMoveToSuperview {
[super didMoveToSuperview];
// Add constraints to super view
if (self.superview) {
[self mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.superview.mas_left);
make.top.equalTo(self.superview.mas_top);
make.width.mas_equalTo(self.superview.bounds.size.width);
make.height.equalTo(@36);
}];
}
}
一定要记住虽然名字是 MoveToSuperview,但是移除的时候也会调用,这时候 self.superview 已经为nil,所以要做 if 判定,不然会crash。
这里宽度我用的是计算宽度,因为父视图是scrollView,不指定宽度的话scrollView会被撑大,所以不能直接设定右侧约束,我就因为这个坑踩了很久才出来。
- (void)layoutSubviews
我一开始以为用了上面的方法就万事大吉了,但是却不够。因为我在上面的方法里用了superView的bounds。
和前文提到的一样,虽然是用的约束,但是这个对于屏幕宽度的计算依然是一次性的,在屏幕旋转的时候虽然约束会更新视图,但是width被我们钉死了。所以需要在更新视图的时候更新约束去获取最新的宽度信息:
- (void)layoutSubviews {
[super layoutSubviews];
[self mas_updateConstraints:^(MASConstraintMaker *make) {
make.width.mas_equalTo(self.superview.bounds.size.width);
}];
}
网友评论