18-4-29【AutoLayout学习笔记】

Layout学习笔记


AutoLayout

布局过程

AutoLayout的布局过程可大致分为三步:

Step1.更新约束
将所需要用到的布局信息测量出来,可以用方法         `setNeedsUpdateConstraints`手动触发本过程,也可以通过对自身约束系统的改变来自动触发该过程。对于定制的VIew,可以重写`updateConstraints`来添加定制的局部约束
Step2.进行布局
布局是从上到下依次进行的,可以用`setNeedsLayout`手动触发这个过程,而该方法只是将请求记录下来随后刷新,而非立刻请求进行布局。之后再调用`layoutIfNeeded`来触发布局。同样的,也可以通过重写`layoutSubview`来获得布局这个过程的控制权。
Step3.显示/渲染
最后将整个view渲染到屏幕上,也是从上到下依次进行。可以调用`setNeedsDisplay`来手动触发,将所有的请求整合后延时重绘。对于需要定制的View,可以重写`drawRect`来获得显示过程的控制权。
相关方法
1. `setNeedsUpdateConstraints` : 将 view 标记为需要更新约束,并在稍后触发`updateConstraitsIfNeed`
2. `updateConstraitsIfNeed`:系统会在每个布局节点自动调用此方法。只有约束被标记为需要更新才会调用`updateConstraints`。此方法可以手动调用。子类不要重写此方法。
3. `updateConstraints`:更新约束的实际方法。
4. `setNeedsLayout`:将 view 标记为需要更新布局,并在稍后触发`layoutIfNeeded`。当view的布局改变时会自动调用。
5. `layoutIfNeeded`:系统会在每个布局节点自动调用此方法。只有布局被标记为需要更新才会调用`layoutSubViews`
6. `layoutSubViews`:在 iOS5.1 之后的是更新布局的实际方法,之前没有默认实现。只有当 autoresizing 和 constraint 不能满足布局需求时才能重写。不能直接调用。会调用`updateConstraintsIfNeeded`
7. `setNeedsDisplay`:将 view 标记为需要重绘,并在下次绘制循环触发 `drawRect`。改变布局不会触发此方法。
8. `drawRect`:没有默认实现。不能直接调用。

原理

AutoLayout是通过多个视图之间的**约束关系**计算出相应的位置坐标,从而来达到自动布局的效果。
18-4-29【AutoLayout学习笔记】

RedView的位置由BlueView和两者之间的约束关系计算得出

优先级

概要:
在Autolayout中每个约束都有一个优先级,优先级的范围是1 ~ 1000,默认创建的约束优先级是最高的1000。约束优先级的核心就是**哪个约束的优先级高,就使用哪个约束**
解决思路
当两个/多个约束发生冲突时,通过调整其优先级,让优先级高的约束生效。一般默认的优先级为1000,在调整后,优先级低的约束会变成**虚线**
Example:左右两个 view A 和 B。实现:当让 A 消失时,B 向左平移
需要建立两套约束,一套是A,B之间的约束关系,一套是B与subview间的约束关系,并且是前一套的优先级大于后一套的优先级。这样的话,当A存在时,会默认使用第一套约束,而当A消失后,第一套约束无法使用,转而使用优先级低的第二套约束,从而达到B向左平移的效果。

第三方库(SnapKit/Masonry)

Masonry是一个优秀的第三方自适应库,它可以让iOS、OS X应用更加简单的实现自动布局(AutoLayout),而SnapKit则是Masonry的Swift版本。
二者的Github地址:

SnapKit:`https://github.com/SnapKit/SnapKit`

Masonry:`https://github.com/SnapKit/Masonry`

由于内容过多,在此不一一介绍,可见`http://www.hangge.com/blog/cache/detail_1097.html`

对比几种Layout

AutoLayout

最常用的一种Layout,相比于Frame,AutoLayout只需描述各个视图间的关系即可,但面对比较复杂的约束时,需要进行大量的运算,所以可能会影响性能。

Frame

Frame是纯坐标布局,在灵活性上肯定优于Autolayout,但是它的缺点在于大量的数据会让维护变得相对困难。对于动态的视图来说,Frame整体更加优秀。

AutoResizing

AutoResizing是苹果早起的UI布局适配的解决办法,一般用于iOS6之前,而AutoResizing是一个相对于父控件布局的解决方法,即它只能相对于父控件布局。

Sizeclass

在iOS 8中新增的Sizeclass,它是对当前所有iOS设备尺寸的一个抽象。由于目前OS设备的尺寸越来越多,按以前的布局方案只会越来越麻烦,苹果新增的Sizeclass提出了一种解决的方案:你不是设备多吗,那我们就只把屏幕的宽和高分别分成三种情况:(Compact, Regular, Any),也即紧凑、正常和任意。这样宽和高三三一整合,一共9钟情况。

相关链接:`https://www.jianshu.com/p/f20a0e92ea76`

Xib

Xib多用于一些自定义的控件的布局,但是其固定的数值约束,在面对不同设备,不同尺寸的屏幕时,Xib并不能做到完美的适配,所以和其他Layout结合使用才是一种比较合理的布局方案。

UIStackView

UIStackView是iOS 9中新增的控件。他提供了一组接口用于平铺一行或者一列的的视图组合.对于嵌入StackView的视图,我们无需在进行任何约束了,UIKit已经帮忙最好了一切约束布局,也就是能自动适应不同屏幕.而且你可以在一个StackView内嵌入多个StackView来完成更为复杂的界面要求,简单来说,他节省了很大一部分时间给每个UI元素创建约束,它继承UIView,因此也会有很酷炫的动画.而对于一般的情况,UIStackView 比较适合用来实现有对齐要求的视图布局。

PS:UIStackView虽然继承自UIView,但是并不参与屏幕的渲染,重写drawRect:方法也是无效的。

性能

造成卡顿的原因

用AutoLayout对复杂视图进行布局。随着视图数量的增长,Autolayout 带来的 CPU 消耗会呈指数级上升。(?原因未知)

解决方案

手动调整**frame**等属性,或使用 ComponentKit、AsyncDisplayKit 等框架。

 下图是使用autolayout和使用frame设置, 在view数量增加后,所消耗时间的对比。 
18-4-29【AutoLayout学习笔记】)

ASDK(Texture)

 AsyncDisplayKit(简称 ASDK)是由 Facebook 开源的一个 iOS 框架,能够帮助最复杂的 UI 界面保持流畅和快速响应。

ASDK 对于绘制过程的优化有三部分:分别是栅格化子视图、绘制图像以及绘制文字。


   它拦截了视图加入层级时发出的通知 - willMoveToWindow: 方法,然后手动调用 - setNeedsDisplay ,强制所有的 CALayer 执行 - display 更新内容; 


   然后将上面的操作全部抛入了后台的并发线程中,并在 Runloop 中注册回调,在每次 Runloop 结束时,对已经完成的事务进行 - commit ,以图片的形式直接传回对应的 layer.content 中,完成对内容的更新。 


  从它的实现来看,确实解决了很多昂贵的 CPU 以及 GPU 操作,有效地加快了视图的绘制和渲染,保证了主线程的流畅执行。