孕孕的三个问题之——为什么使用 Auto Layout 之后手动修改 frame 无效
刚开始使用 Auto Layout 的时候,我应该都经历过神奇的“bug”:手动设置 frame 值不管用,通过修改 frame 进行的动画出现了“反向运动”的奇特效果,而且动画时间也大幅缩短,非常奇怪。
这涉及到了 Auto Layout 本身的特性,我们先来看一段苹果的文档:https://developer.apple.com/library/prerelease/ios/documentation/UserExperience/Conceptual/AutolayoutPG/index.html
External Changes(外部变化)
下面是一些会引发 Auto Layout 重新排布的常见外部变化情况:
- OS X 上用户改变了窗口大小
- 使用或者退出 iPad 上的 Split View
- iOS 设备屏幕方向旋转
- iOS 上全局置于屏幕顶部的“电话中”及“录音中”提示条
- 我们想要支持不同的 size classes
- 我们想要支持不同的屏幕尺寸
Internal Changes(内部变化)
下面是一些会引发 Auto Layout 重新排布的常见内部变化情况:
- 内容发生了变化
- 支持国际化的 APP 在语言改变时
- iOS 中的 Dynamic Type(例如用户自定义文字大小)
从上面的文档中,我们应该可以初窥端倪了:
- Auto Layout 在得到当前屏幕尺寸后开始工作
- Auto Layout 在内容发生变化需要更新布局时会重新排布界面
- Auto Layout 是一种完全不同于之前使用代码计算 frame 的全新界面组织方式
Auto Layout 是一种新的界面组织引擎,其界面组织逻辑不遵循之前手动构建 UI 组件、手动设定尺寸和位置的基本逻辑。实际上有过实际的使用经验你就会发现,Auto Layout 具有跟传统代码组织 UI 布局完全不一样的行为方式:
- 容器驱动:先显示界面,拿到屏幕尺寸,再重新排布 UI
- 内容驱动:修改内容,会触发 UI 的重新排布和重绘
- 底层一致:依然遵循基础的 iOS UI 渲染原则和流程
- 对于第三点打一个比方可能更容易理解:Auto Layout 更像是 HTTP 层的透明代理,而手写代码依然工作在 IP 层;Auto Layout 更加方便使用,但是跟手写代码比起来更上层、更慢、约束更多。
回到我们标题中提出的问题:为什么使用 Auto Layout 之后手动修改 frame 无效?经过我们上面的分析可以发现,手动修改 frame 工作在更底层,不可能无效。
其实是有效的,但是这个“效”并不是我们想要的“效”而已。如果你在使用了 Auto Layout 的界面上像通过修改 frame 来做动画,你就会发现神奇的事情:你定义了 500 ms,一个按钮从下往上动 100px,实际上你会看到一个神奇的快速动画:很短时间内(估计为几毫秒到十几毫秒),这个按钮从上往下移动了 100px,这是为什么呢?因为在使用了 Auto Layout 的页面中,代码修改 frame 会在一瞬间完成,不会再像之前那样按照既定的 500ms 做完动画;而就在 frame 被瞬间修改之后,Auto Layout 的布局引擎侦测到了~~在途的聚变打击~~内容发生了变化,启动了重绘机制,UI 会重新排布为之前约束规定的样子,而由于 Auto Layout 布局系统的“低性能”,我们就看到了奇怪的“快速反向动画”。
那么 Auto Layout 系统下的动画如何做呢?其实非常简单,把之前修改 frame 的代码变为修改约束值即可,详情可以查看我的 Keynote:https://github.com/johnlui/AutoLayout
要是你说:我就是傲娇,我就想用修改 frame 的方式修改被 Auto Layout 约束的元素,怎么办?这里有一个高票的解决方案,我想你可以试试:Can I use setFrame and autolayout on the same view?
发表评论: