首先明确两个概念:
- UIWindow 对象 : 整个程序中视图层次结构中最顶层,充当一个容器类。
- UIViewController 对象 :viewController 中一个 view属性是 view层次结构中rootView,可以添加 view构建复杂的视图结构,通过生命周期方法loadView、viewDidLoad、viewWillAppear 等控制视图声明周期,因为他继承于 UIResponder,所以可以响应和处理用户事件。
- View、 Control 、 Layer 对象 :view可以通过 addSubView 和 removeFromSuperView等方法管理视图层次结构,使用 layoutSubviews、layoutIfNeeded 和 setNeedsLayout 等方法布局 view的层次结构,当系统提供的 view无法满足需要,可以重写 drawRect 方法或者通过 layer属性构造更加复杂的图形和动画。
iOS中布局相关方法
- - (CGSize)sizeThatFits:(CGSize)size;
- - (void)sizeToFit;
sizeToFit 自动调用 sizeThatFits 方法,不能在子类中重写 sizeToFit
----------------------------------------------------------------------
- - (void)layoutSubViews;
- - (void)layoutIfNeeded;
- - (void)setNeedsLayout
layoutSubviews 在以下情况下会被调用
- init初始化不会触发 layoutSubviews,但是 initWithFrame 进行初始化会被调用,当 rect 的值不为 CGRectZero 时,也会触发。
- addSubView会触发 layoutSubviews
- 设置 view的 frame 会触发 layoutSubviews
- 滚动 ScrollView 时会触发 layoutSubviews
- 旋转 Screen 会触发 父view 上的 layoutSubviews
- 改变一个 view的大小也会触发父view的 layoutSubviews,所以重写这个方法要调用 [super layoutSubViews]
setNeedsLayout 标记需要刷新布局的控件,下一次运行循环的时候会刷新布局,异步调用 layoutIfNeeded——>layoutIfNeeded,立即刷新布局——>layoutSubViews
---------------------------------------------------------------------
- - (void)setNeedsDisplay;
- - (void)drawRect;
setNeedsDisplay 方法,标记为重绘,异步调用 drawRect 方法
drawRect 方法,重写此方法,执行重绘任务
这个两个方法都没没有递归,对 subViews 也不负责,只负责自己。
---------------------------------------------------------------------
layoutSubviews对subviews重新布局
layoutSubviews方法调用先于drawRect
setNeedsLayout在receiver标上一个需要被重新布局的标记,在系统runloop的下一个周期自动调用layoutSubviews
layoutIfNeeded方法如其名,UIKit会判断该receiver是否需要layout.根据Apple官方文档,layoutIfNeeded方法应该是这样的
drawRect是对receiver的重绘,能获得context
setNeedDisplay在receiver标上一个需要被重新绘图的标记,在下一个draw周期自动重绘,iphone device的刷新频率是60hz,也就是1/60秒后重绘