前言
在之前 IOS xib 或 Storyboard xib view 创建布局及手动修改frame 这篇文章中简单说明了 xib view 的创建及修改 frame 问题,但是可能满足不了一些项目的需求,例如:在 View 创建完成添加到父视图后,需要在xib View 中某个位置添加多个自定义的小View,显然这个时候单纯修改 XibView frame 就无法满足了。
效果如下:
IMG_726AC6FDC4D9-1.jpeg
外面的为一个 大的 XibView , 有背景颜色的为新添加的小的 View,点击添加途经点可以无限添加。
解决方法一
笨办法就是每次添加重新计算 影响 大的 XibView 的子控件的位置,然后重新设置,也算是一种方法,但是这样很麻烦。
解决方法二
苹果提供的 Autolayout ,用代码来添加约束,这也有几种不同的方式。
-
使用 苹果原生的 约束布局,NSLayouyConstraint。
-
使用基于 NSLayoutConstraint 封装的第三方布局框架 Masonry 。
-
使用基于 NSLayouyConstraint 的一个非常轻量级的三方框架 UIView+AutoLayout。
先贴出github地址:https://github.com/jrturton/UIView-Autolayout
NSLayouyConstraint 介绍
NSLayouyConstraint,API 较繁琐,代码量很多,而且大多都是重复性的代码,以至于好多人都不想用这个框架。但使用还比较简单,下面细述。
在给控件添加约束的过程中,主要是这个方法
NSLayoutConstraint *left = [NSLayoutConstraint constraintWithItem:addPointView attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:carView.viaView attribute:NSLayoutAttributeLeft multiplier:1.0 constant:0];
[addPointView addConstraint:height];
[addPointView addConstraints:@[left,right]];
一个是添加的数组,一个添加属性约束.
两点必须说明:
1:控件初始化的时候不要设置他 frame。
2:也是重中之重的,不然会导致严重的性能问题,一定要对当前控件的
translatesAutoresizingMaskIntoConstraints的属性设置为NO,不然无法使用。。。
首先看看这两个约束的方法
具体参数
constraintWithItem:要设置的控件的名称
attribute:要设置的控件的属性
relatedBy:相对关系(NSLayoutRelationEqual)
toItem:相对于哪个视图
attribute:相对于哪个视图的属性
multiplier:相对缩放比例
constant 设置的固定值
可以看 API 的注释
/* Create constraints explicitly. Constraints are of the form "view1.attr1 = view2.attr2 * multiplier + constant"
If your equation does not have a second view and attribute, use nil and NSLayoutAttributeNotAnAttribute.
*/
+(instancetype)constraintWithItem:(id)view1 attribute:(NSLayoutAttribute)attr1 relatedBy:(NSLayoutRelation)relation toItem:(nullable id)view2 attribute:(NSLayoutAttribute)attr2 multiplier:(CGFloat)multiplier constant:(CGFloat)c;
- AutoLayout 代码约束—VFL(Visual Format Language)
下面开始说约束的VFL代码
/**
* VFL创建约束的API
*
* @param format 传入某种格式构成的字符串,用以表达想要添加的约束,如@"H:|-margin-[redView(50)]",水平方向上,redView与父控件左边缘保持“margin”间距,redView的宽为50
* @param opts 对齐方式,是个枚举值
* @param metrics 一般传入以间距为KEY的字典,如: @{ @"margin":@20},KEY要与format参数里所填写的“margin”相同
* @param views 传入约束中提到的View,也是要传入字典,但是KEY一定要和format参数里所填写的View名字相同,如:上面填的是redView,所以KEY是@“redView”
*
* @return 返回约束的数组
*/
/* Create an array of constraints using an ASCII art-like visual format string.
*/
+ (NSArray<__kindof NSLayoutConstraint *> *)constraintsWithVisualFormat:(NSString *)format options:(NSLayoutFormatOptions)opts metrics:(nullable NSDictionary<NSString *,id> *)metrics views:(NSDictionary<NSString *, id> *)views;
NSDictionary * views = NSDictionaryOfVariableBindings(view1,view2); NSLayoutConstraint *constraint = [NSLayoutConstraint constraintsWithVisualFormat:@"|-30-[lastPointView]-30-|" options:0 metrics:nil views:<#(nonnull NSDictionary<NSString *,id> *)#> views]
它的API短了一些,但是要筹齐参数是件很麻烦的事
字典类型参数的views 是要添加约束的对象的集合,opts 为 NSLayoutFormatOptions 枚举。
最重要的就是format参数,而这个参数的难点在于其书写格式:
每句前面都要加@"H:"或者@"V:",分别代表着水平和垂直方向
@"|"代表着边界
@"-"用来表示间隙,一般以这样的形式出现@"-20-",这代表20的间距,也可以填写标识,如@"-margin-",之后设置替换参数metrics
@"[]"中括号里放的就是要添加约束的View,如上边例子的redView,想要设置宽度或者度,就这样[redView(50)],水平方向(H:)填写这个数字代表的就是宽,垂直方向就是高(V:)
小结
- VFL实现Autolayout是有局限性的,使用起来并不是那么的方便,随心所欲。
- 这里VFL仅供大家了解,建议大家使用 Masonry 这个第三方来实现Autolayout,Masonry 这个框架相信大家都用的很熟悉了。
Masonry 简单使用及分析
Github地址:
https://github.com/SnapKit/Masonry
Masonry基于NSLayoutConstraint封装的第三方布局框架Masonry使用起来非常方便,Masonry采取了链式编程的方式,代码理解起来非常清晰易懂,而且写完之后代码量看起来非常少,但是 Masonry 也有一些缺陷和问题。
Masonry中的坑
在使用Masonry进行约束时,有一些是需要注意的。
- 在使用Masonry添加约束之前,需要在addSubview之后才能使用,否则会导致崩溃。
- 在添加约束时初学者经常会出现一些错误,约束出现问题的原因一般就是两种:约束冲突和缺少约束。对于这两种问题,可以通过调试和log排查。
- 之前使用Interface Builder添加约束,如果约束有错误直接就可以看出来,并且会以红色或者黄色警告体现出来。而Masonry则不会直观的体现出来,而是以运行过程中崩溃或者打印异常log体现,所以这也是手写代码进行AutoLayout的一个缺点。
这个问题只能通过多敲代码,积攒纯代码进行AutoLayout的经验,慢慢就用起来越来越得心应手了。 - 用 Masonry添加约束之后,可能需要用代码来获取或修改 frame,而立即获取 frame 是获取不到的,因为加载顺序的先后问题,需要延迟调用 dispatch_after 才可以。
延迟 0 s 就可以。
//定义一个C函数,用来简单封装一下dispatch_after
void didLayout(void(^layout)(void)) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
if (layout) layout();
});
}
具体怎么使用就不说了,大家应该都用的很熟练了,API 一看大概就明白了。
UIView-Autolayout 的简单使用
最后说一下 UIView-Autolayout 的简单使用,众所周知的Autolayout可以在storyboard里通过添加约束来实现,这样是比较简单的.如果用代码的话,是比较麻烦的,包括用VLF语言开发效率也不是很高.那么这里给大家推荐一个非常轻量级的三方框架,准确来说也不算是一个框架,它是给UIView添加一个分类,使用起来非常简单.
类似如下:
[addPointView autoPinEdge:ALEdgeTop toEdge:ALEdgeTop ofView:carView.viaView withOffset:0];
[addPointView autoPinEdge:ALEdgeLeft toEdge:ALEdgeLeft ofView:carView.viaView withOffset:0];
[addPointView autoPinEdge:ALEdgeRight toEdge:ALEdgeRight ofView:carView.viaView withOffset:0];
[addPointView autoSetDimensionsToSize:CGSizeMake(ScreenW, 50)];
只是一个添加了一个 category ,API 一看就明白了,使用也很顺手,用 XibView 和 代码结合也很好用,强烈推荐大家使用,自认为是这几种方式中最简单最实用的方式。
网友评论