AutoLayout

883 阅读2分钟

一、自动布局的原理

1、Constraints Change 激活,失活 创建约束,优先级 添加,移除视图 检测到改变后系统(Layout Engine) 会重新计算出布局,就会调用superview.setNeedsLayout()

2、Deferred Layout Pass 容错处理 从上往下调用layoutSubviews() 从 Layout Engine 拷贝出子视图 frame

到此,系统就计算好frame了,接下来就是渲染了,和手写布局是一样的

3、Application Run Loop

Layout Engine 通过系统RunLoop 循环cycle

整个流程可以理解为,当修改约束的时候,会触发Layout Engine去计算出view的frame,然后从上而下布局,最后在下一个运行循环中更新界面。

layoutSubviews

layoutSubviews在以下情况下会被调用:

1.1、View init 初始化不会触发layoutSubviews

View 的 frame 为 0 时,addSubView也不会调用layoutSubViews;

但是是用 initWithFrame 进行初始化,当rect的值不为 CGRectZero 时,会触发View的LayoutSubViews;

1.2、View直接调用setLayoutSubViews

1.3、子控件addSubview会触发View的layoutSubviews;(最常用)

1.4、子控件的frame发生改变时,会调用View的layoutSubViews

1.5、View的 frame 发生变化时,会调用父控件的LayoutSubViews

1.6、父控件的frame发生变化时,会调用View的layoutSubViews

1.7、滚动一个UIScrollView会触发View的layoutSubviews

1.8、旋转Screen会触发父控件的layoutSubviews事件(控制器的ViewWillLayoutSubView)

drawRect

重写此方法,执行重绘任务

drawRect调用机制:以下1、2推荐;而3、4不提倡

2.1、如果在UIView初始化时没有设置rect大小,将直接导致drawRect不被自动调用;

2.2、该方法在调用sizeThatFits后被调用,所以可以先调用sizeToFit计算出size。然后系统自动调用drawRect:方法;

2.3、通过设置contentMode属性值为UIViewContentModeRedraw。那么将在每次设置或更改frame的时候自动调用drawRect;

2.4、直接调用setNeedsDisplay,或者setNeedsDisplayInRect:触发drawRect:,但是有个前提条件是rect不能为0。

sizeToFit

sizeToFit: 会计算出最优的 size 而且会改变自己的size;

sizeThatFits:会计算出最优的 size 但是不会改变 自己的 size

UIView的sizeToFit 和 NSString 的boundingRectWithSize: options: attributes: context: 方法非常耗性能,不适合频繁调用的场景,否则有可能会造成卡顿。