iOS的布局视图约束

本文详细阐述了iOS应用中主runloop如何处理用户输入事件,并介绍了事件处理后的更新周期(UpdateCycle),包括布局、视图显示和约束的更新。重点讲解了layoutSubviews、setNeedsLayout、draw方法及其触发条件,以及updateConstraints和约束系统的工作原理。通过理解这些机制,开发者可以更高效地管理应用的性能和用户体验。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

iOS应用的主runloop负责处理所有用户输入事件并触发响应,所有交互放在事件队列中
下图的application object会从队列中取出事件并分发到其他对象,本质上会解释来自用户的
输入事件,然后调用core obj方法,这些代码调用开发者代码,当这些方法调用返回后,控制
流回到回到主runloop上,然后开始update cycle 就是周期更新,周期更新负责重新渲染所有的视图
下图展示了应用是如何和设备交互并处理用户输入的

Update Cycle 是应用完成了所有事件的处理代码后 控制流回到主runloop的节点 
正是这个时间点 开始更新布局 显示 设置约束
如果在处理事件代码中修改了一个view 那么系统会把这个view标记为需要重画的redraw
接下来的update cycle会执行这些view的更改 而且延时几乎察觉不到
一般为60fps 就是更新周期为1/60秒的时间
但是处理事件和对应的view的重绘会有时间间隔 runloop中的某个时刻的view更新可能
不是你想象的那样 所以需要知道布局视图约束的关系
下图展示出 update cycle发生在runloop尾部

布局 
一个视图在屏幕上大小和位置 相对父视图的 UIView提供了用来通知系统某个view布局发生变化
的方法 还有布局重新计算后调用可重写的方法


layoutSubviews
这个方法对视图及所有子视图重新定位和大小调整 开销大 因为它会给子视图调用他们相应的layoutSubvieews
所以需要更新frame来重新定位或者更改大小时重载它
代码中不能显式调用 可以在runloop不同时间点触发layoutSubvieews
资源消耗比直接小很多

哪些方法可以触发自动刷新触发器
有许多事件会自动给视图打上 uopdate layout 标记 因此layoutSubvieews会在下个周期调用 不需要开发者手动操作
1 修改view的大小
2 新增subview
3 在UIScrollview上滚动 
4 旋转设备
5 更新视图的constraints

setNeedsLayout
触发这个方法调用是最省资源的 这个方法会立刻执行并返回 返回钱不会更新视图 会在下个update cycle更新

layoutIfNeed
这个会让view触发layoutSubviews的方法 layoutIfNeed和setNeedsLayout不同的是 它会立刻调用layoutSubviews这个方法
不会等到下次的update cycle 
但是没有任何操作向系统标明需要刷新视图 那么就不会调用layoutSubviews
通常配合动画执行之后的block用

视图
一个视图显示包含了颜色 文本 图片 coreGraphics绘制等视图属性 不包含本身和子视图大小和位置
和布局类似 显示也有触发更新的方法 由系统检测时更新 或者手动更新

draw方法 
对视图的显示操作 类似于视图布局的layoutSubviews 但是不同于layoutSubviews draw不会触发后续子视图的方法调用
不能直接调用 而是在系统的runloop中不同节点自动调用

setNeedsDisplay
这个方法类似于布局中的layoutIfNeed 它会给内容更新视图一个标记 但在视图重绘之前就会返回
在下一个update cycle  遍历所有标记的视图 并调用他们的draw方法

约束
主要包含了视图和布局之间的关系 因为它们彼此不是孤立的 而是相互有关系的
主要分为3步 第一步是更新约束 系统计算出视图设置所有要求的约束
第二步是布局阶段 布局引擎计算视图和子视图的frame 并且将它们布局
最后一步是显示

updateConstraints
这个方法动态改变视图的约束 和布局的layoutSubvieews和显示的draw方法 这个方法只应该被重载
通常情况下 设置或者解除 或者更改约束的优先级或者常量值 或者从视图层级中移除一个视图都会
设置一个内部的标记 update constraints 这个标记会在下个周期中触发调用updateConstraints

setNeedsUpdateConstraints
这个方法保证下个更新周期更新约束

updateConstraintsIfNeeded
这个方法和布局中的layoutIfNeeded等价 如果需要会直接触发 不会等到run loop的末尾

invalidateIntrinsicContentSize
自动布局某些视图拥有intrinsicContentSize属性 这是视图根据内容获得的自然尺寸 一个视图的intrinsicContentSize
通常由里面的内容决定
调用invalidateIntrinsicContentSize 会设置一个标记表示intrinsicContentSize已经过期 需要再下一个周期重新计算

如何连接起来
下图比较好的总结

下面的流程总结了update cycle和event loop之间的交互
如果显式调用layoutIfNeeded 或者 updateConstraintsIfNeeded 开销会很大
可以通过设置“update constraints”,“update layout” 或者 “needs display” 标记
在下个刷新周期进行布局 视图 约束的更新

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值