我们从 View Controller 的生命周期来分析这个问题:
viewDidLoad viewWillAppear viewWillLayoutSubviews viewDidLayoutSubviews viewDidAppear viewWillDisappear viewDidDisappear |
Auto Layout 的布局是从外到内的,即从屏幕尺寸开始布局,一直布局到最里面的细节元素,我们的目光自然地落在了 viewDidLayoutSubviews
和 viewDidAppear
上了:
- viewDidLayoutSubviews 时当前视图已经把子元素布局完毕,frame 已经形成
- viewDidAppear 时,渲染系统把当前视图加入父视图中,显示在屏幕上
所以,解决方案其实已经水落石出了:
- 避免调用 layoutSubviews,在 viewDidLayoutSubviews 和 viewDidAppear 中进行 frame 的获取
- 如果你需要尽早地做一些大动作,推荐在 viewDidLayoutSubviews,此时用户还没有看到 UI,用法可以更灵活
- 注意 viewDidLayoutSubviews 可能会被多次调用,所以添加元素之类的操作尽量避免在这里做
- viewDidAppear 中可以干一切你想干的事情,但是一些需要用户看到的东西例如动画只能在这里做
- 更推荐把需要做的事情尽量全部放到 viewDidAppear 中来做,让用户尽早地看到界面,这是人机交互的基本原则
回到标题中的问题:什么时候才能获得正确的 frame? 在 viewDidLayoutSubviews
和 viewDidAppear
中。