UIView的setNeedsDisplay和setNeedsLayout方法

首先两个方法都是异步执行的。
setNeedsDisplay会调用自动调用drawRect方法,这样可以拿到 UIGraphicsGetCurrentContext,就可以画画了。
setNeedsLayout会默认调用layoutSubViews,这样就可以处理子视图中的一些数据。
综上所诉,setNeedsDisplay方便绘图,而layoutSubViews方便出来数据。

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

1、init 初始化不会触发 layoutSubviews.
2、addSubview 会触发 layoutSubviews.
3、设置 view 的 Frame 会触发 layoutSubviews,当然前提是 frame 的值设置前后发生了变化.
4、滚动一个 UIScrollView 会触发 layoutSubviews.
5、旋转 Screen 会触发父 UIView 上的 layoutSubviews 事件.
6、改变一个 UIView 大小的时候也会触发父 UIView 上的 layoutSubviews 事件.
7、直接调用 setLayoutSubviews.

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

1、如果在 UIView 初始化时没有设置 rect 大小,将直接导致 drawRect 不被自动调用。drawRect 调用是在 Controller->loadView, Controller->viewDidLoad 两方法之后调用的,所以不用担心在控制器中,这些 View 的 drawRect 就开始画了,这样可以在控制器中设置一些值给View (如果这些View draw的时候需要用到某些变量值)。

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

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

4、直接调用 setNeedsDisplay,或者 setNeedsDisplayInRect: 触发 drawRect:,但是有个前提条件是 rect 不能为0。
以上1,2推荐;而3,4不提倡。

drawRect方法使用注意点:

1、若使用 UIView 绘图,只能在 drawRect:方法中获取相应的 contextRef 并绘图。如果在其他方法中获取将获取到一个invalidate 的 ref 并且不能用于画图。drawRect:方法不能手动显示调用,必须通过调用 setNeedsDisplay 或者 setNeedsDisplayInRect,让系统自动调该方法。

2、若使用 calayer 绘图,只能在 drawInContext: 中(类似于drawRect)绘制,或者在 delegate 中的相应方法绘制。同样也是调用 setNeedDisplay 等间接调用以上方法。

3、若要实时画图,不能使用 gestureRecognizer,只能使用 touchbegan 等方法来掉用 setNeedsDisplay 实时刷新屏幕。

原文链接