读Masonry源码
读读让写自动布局时可以帮忙解放双手的 Masonry源码
如果不使用第三方库,使用自动布局的话,苹果提供两种方式:
- NSLayoutConstraint,缺点是常见约束的代码冗长,描述性不强;
- VFL(Visual Format Language),苹果为了简化Autolayout的编码而推出的可视化格式语言;缺点为基于字符串,不支持存在倍数关系的约束,是NSLayoutConstraint子功能集;NSLayoutConstraint constraintsWithVisualFormat:方法返回数组类型,难以进行单个约束的动画处理;
针对这些缺点,Masonry有哪些改进呢,官网文档上有特征介绍:
- NSLayoutConstraint 能做到的,Masonry也能做;
- 出色的调试支持,为视图和约束提供了有意义的名称;
- 没有疯狂的宏魔法,不会用宏污染全局命名空间;
- 支持编译检查,因为没有基于字符串或字典;
原生写法:
UIView *superview = self.view;
UIView *view1 = [[UIView alloc] init];
view1.translatesAutoresizingMaskIntoConstraints = NO;
[superview addSubview:view1];
UIEdgeInsets padding = UIEdgeInsetsMake(10, 10, 10, 10);
[superview addConstraints:@[
//view1 constraints
[NSLayoutConstraint constraintWithItem:view1
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:superview
attribute:NSLayoutAttributeTop
multiplier:1.0
constant:padding.top],
]];
Masonry写法:
UIEdgeInsets padding = UIEdgeInsetsMake(10, 10, 10, 10);
[view1 mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(superview.mas_top).with.offset(padding.top);
}];
的确是精简了很多,那Masonry是怎么做到的呢? 不可能封装的VFL,所以只会是对NSLayoutConstraint的封装;
对比直接使用NSLayoutConstraint,猜测mas_makeConstraints: 完成了如下步骤的封装:
- 猜测1 调用的view 设置属性 .translatesAutoresizingMaskIntoConstraints = NO;
- 猜测2 封装了 NSLayoutConstraint 创建过程,可能是 block中的 make.top.equalTo…
- 猜测3 mas_makeConstraints: 执行 相当于 addConstraints: 过程;
但是 查看方法声明
- (NSArray *)mas_makeConstraints:(void(NS_NOESCAPE ^)(MASConstraintMaker *make))block;
为啥有数组型返回值?可能是用来做动画的吧,没用过…聊胜于无吧,看SnapKit同样的方法返回的void;
MAS_VIEW (MASAdditions)
- (NSArray *)mas_makeConstraints:(void(^)(MASConstraintMaker *))block {
self.translatesAutoresizingMaskIntoConstraints = NO;
MASConstraintMaker *constraintMaker = [[MASConstraintMaker alloc] initWithView:self];
block(constraintMaker);
return [constraintMaker install];
}
以UIView的分类形式,猜测1没问题; MASConstraintMaker调用了 initWithView、install两个方法;
initWithView方法,只是弱引用了当前view,初始化一个用于保存约束的数组constraints而已;
install会调用MASConstraintMaker->MASViewConstraint中的install方法,最终调用[self.installedView addConstraint:layoutConstraint];
疑问?上一步中layoutConstraint需要的参数都是怎么来的 ?
block(constraintMaker);传入了maker参数,里做了什么?
make.top.equalTo(superview.mas_top).with.offset(padding.top);
这句代码到底做了什么?将block中写的约束依次创建为MASViewConstraint然后加入maker的属性数组constraints中,单句代码返回值为刚才创建的MASViewConstraint(官方给的例子中有把当前返回值保存到数组中,然后做动画的例子,这样就避免了VFL一次性数组返回而过程不透明的弊端);
DSL (domain specific language)是什么 ?
领域特定语言,指专注与某个应用程序领域的计算机语言;
某位大佬的结论是:
绝大部分DSL的存在是设计者没有理解问题的本质;绝大部分的问题可以通过“库代码”来解决,而不是DSL;
补全了哪些知识点
- 有个ViewController+MASAdditions分类,添加了self.view的部分快捷属性,但NS_DEPRECATED_IOS(8.0, 11.0);
- 有个NSArray+MASAdditions数组的分类,mas_distributeViewsAlongAxis:,看一下官方的例子,挺好用的,线性布局方式看起来很像UIStackView的Api,或者Flex布局(Axis,轴)阮一峰的 Flex 布局教程:语法篇