History and Something Insteresting
手写代码的UI的自动布局在iOS6中引入的新特性iOS 6 brings an awesome new feature to the iPhone and iPad: Auto Layout, 以取代之前的 autoresizingMask( “springs and struts” Model).
实际上关于纯手写代码UI Layout经历了三个时期,固定宽高(这个用frame设计非常容易),AutoresizingMask以及最新的Autolayout. 由于iphone6/6S发布后,苹果手机屏幕尺寸呈现多样性,所以Autolayout为APP开发提供了便捷的UI布局方案。
Masonry是一个轻量级的Layout框架,采用更自然的链式语法封装autolayout,同时支持iOS和Mac OS X.
Auto Layout 已经集成到Xcode5 + 版本的开发环境中,新建项目将默认开启Auto Layout.
Usage
- Step1 将Masonry库添加到工程中
//编辑Podfile文件,添加(可以使用 pod search masonry 查询最新支持版本)
pod ‘Masonry‘, ‘~> 0.6.0‘
//然后, 在 Terminate 中输入如下命令
pod install
//或者
pod update
- Step2 在程序文件中使用masonry对视图对象设置约束
//导入头文件:
#import <Masonry/Masonry.h>
// 在Cell中,对属性topBarrier设置Constraints, self.contentView是其父视图
// **注意 equalTo(<对象约束属性>), mas_equalTo(<Value值>)**
// 具体的一些属性含义,可以参加参考文献第一篇
[self.topBarrier mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.contentView).offset(5);
make.left.equalTo(self.contentView.mas_left);
make.width.equalTo(self.contentView.mas_width);
make.height.mas_equalTo(@10);
}];
- Step3 进阶:Masonry创建constraint定义Layout的三种方式
//1. mas_makeConstraints
// 为某个视图对象创建constraint,可以通过设置变量或属性来保存Constraint,并重复利用
// 如 picturesViewTop 这个MASConstraint 类型变量存储了constraint,下次可以复用
[self.picturesView mas_makeConstraints:^(MASConstraintMaker *make) {
MASConstraint *picturesViewTop = make.top.equalTo(self.topBarrier.mas_bottom).offset(5);
make.left.equalTo(self.topBarrier.mas_left);
make.height.mas_equalTo(@(self.pictureHeight));
make.width.mas_equalTo(@(self.pictureWidth));
}];
//2. mas_updateConstraints
// 更新某个视图对象的constraint,而非创建固定constraint
// 下面模拟使用场景
// 重写系统即 UIConstraintBasedLayoutCoreMethods 的 updateConstraints 方法
- (void)updateConstraints
{
[self.pictureView mas_updateConstraints:^(MASConstraintMaker *make) {
make.height.mas_equalTo(@(self.pictureHeight));
make.width.mas_equalTo(@(self.pictureWidth));
}];
[super updateConstraints];
}
// 目的是通过高度和宽度属性(self.pictureHeight,self.pictureWidth)的变化来实现Constraints更新
// 在需要更新的地方添加如下代码, 则会更新相应约束,冲突的Constraints 以更新中的Constraints为准
self.pictureHeight = 100;
self.pictureWidth = 100;
[self setNeedsUpdateConstraints];
[self updateConstraints];
// 3. mas_remakeConstraints
// 和mas_updateConstraints 相似,都是更新Constraints,不同的是 mas_remakeConstraints 会删除之前的Constraints, 然后以新的Constraints 为准。
Important Methods for AutoLayout
- 方法列表
Methods | Function | Usage |
---|---|---|
setNeedsUpdateConstraints | 设置View需要更新约束 下次计算或者更新约束时会更新 |
在需要更新约束的时候调用 确保系统需要更新状态 |
updateConstraintsIfNeeded | 立即触发约束更新,如果有约束要更新 | 系统调用 updateConstraints 方法 实现约束更新 |
setNeedsLayout | 设置View页面需要更新,但不立即执行 | 在需要更新页面布局时调用 |
layoutIfNeeded | 立即触发页面布局更新 | 系统重写布局时调用layoutSubviews 方法 |
- 方法总结
`setNeedsUpdateConstraints` 方法确保系统需要更新约束,系统再调用 `updateConstraintsIfNeeded` 时能确定调用 `updateConstraints` 达到立即更新约束的目的。如果不调用 `setNeedsUpdateConstraints` 且在View上没有约束变化,则系统不会调用 `updateConstraints`。
`setNeedsLayout` 和上述类似原理。
需要注意的是: 系统调用`layoutSubviews`时会调用`updateConstraintsIfNeeded`,通过更新约束,从superView 到 subView的层次顺序来计算frame,反向确定布局。
- Auto Layout Process (自动布局流程)
Step 1 Update Constraints
布局的测量阶段,通过 setNeedsUpdateConstraints 触发
Step 2 layout
通过Step 1 的信息去设置View的 Center和Bounds,自上而下(from super view to subview)通过setNeedsLayout 触发
Step 3 display
把View渲染到屏幕,操作也是自上而下,通过 setNeedsDisplay触发
由于他们有依赖关系,即 update Constraints -> layout -> display, 因此 display 可能触发 layout, layout 可能触发 update Constraints
Issues
问题描述: 使用UITableView+FDTemplateLayoutCell实现Cell高度自适应计算,但在Cell中用Masonry定义的约束不严谨,即没有形成闭环,例如 最后约束的bottom没有加,则masonry计算布局出错,呈现的效果就是叠影。
// tableViewCell中定义的Masonry
[self.commentBarrier mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.elfretweetedBackground.mas_bottom);
make.width.equalTo(self.contentView.mas_width);
make.height.mas_equalTo(@0.5);
}];
[self.commentBar mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.commentbarrier.mas_bottom).offset(5);
make.width.equalTo(self.contentView.mas_width);
make.height.mas_equalTo(@25);
// ****** 注意约束闭环 ******
make.bottom.equalTo(self.contentView.mas_bottom);
}];
// TableViewController 中的TableView代理方法
#pragma mark - UITableViewDelegate
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
// 使用 UITableView+FDTemplateLayoutCell
return [tableView fd_heightForCellWithIdentifier:@"cellIdentifier" cacheByIndexPath:indexPath configuration:^(WeiBoContentTableViewCell *cell) {
// cell 类型
WeiBoDataStatus *status = self.statuses[indexPath.section][indexPath.row];
[cell setupStatus:status];
}];
}
References
Masonry介绍与使用实践(快速上手Autolayout)
Beginning Auto Layout Tutorial in iOS 7: Part 1
版权声明:本文为博主原创文章,未经博主允许不得转载。
时间: 2024-10-24 02:56:44