UIView和CALayer

Posted FarmGuo

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了UIView和CALayer相关的知识,希望对你有一定的参考价值。

1 两者关系

UIView来自UIKit框架,继承自UIResponder,CALayer来自QuartzCore框架,继承自NSObject,更加的底层。
两者互相依赖,UIView是管理CALayer,是对CALayer的封装,可以响应和处理事件。而CALyer则绘制和展示内容。

UIView的很多属性是依赖CALayer实现的,比如frame、bound、center,最终调用了CALayer的frame、bound、position。而Layer的frame则依赖其anchorPotin、position、bounds和transform。

比如UIView的alpha、hidden的获取和设置,就是调用了CALayer的opacty和hidden。

内容的绘制

UIView是CALayer的delgate,通常情况下不参与内容绘制,CALayerDelegate有以下可选方法:

@protocol CALayerDelegate <NSObject>
@optional
- (void)displayLayer:(CALayer *)layer;
- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx;
- (void)layerWillDraw:(CALayer *)layer
- (void)layoutSublayersOfLayer:(CALayer *)layer;
- (nullable id<CAAction>)actionForLayer:(CALayer *)layer forKey:(NSString *)event;

通过实现这些方法,UIView也可以来绘制内容。
-[UIView setNeedsDisplay]方法会标记内容需要更新,在下一个绘制周期到来时,内容会进行更新。
-[CALayer display],会调用delegate(即UIView)的-[UIView displayLayer:]方法。如果未实现,则调用-[CALayer drawInContext: ]。
-[CALayer drawInContext: ]会调用delegate的-[UIView drawLayer:inContext:]方法。
而默认的-[UIView drawLayer:inContext:]方法会尝试调用-[UIView drawRect:]方法。
调用顺序如下,自上而下,如果上面的实现了,则后面的不会被调用。

-[UIView displayLayer:]
-[UIView drawLayer:inContext:]
-[UIView drawRect:]

如果UIView通过重写上面其中一个方法即可参与内容的绘制。
UIView有个contentMode的属性,当设置为UIViewContentModeRedraw时,如果更新bound,也会导致内容更新。

对于自定义的View,通常会重写layoutSubviews方法,在里面更新subview的位置,但这个方法不应该直接调用,而是调用-[UIView setNeedsLayout]或-[UIView layoutIfNeeded],等待系统来更新layout。
前者设置一个标记,等待runloop的下一个周期,进行更新。
后者看是否有更新标记,有则立刻更新,否则直接返回。
所有需要立即更新就这样调用:

-[UIView setNeedsLayout];
-[UIView layoutIfNeeded];

以上是关于UIView和CALayer的主要内容,如果未能解决你的问题,请参考以下文章

UIView与CALayer的区别

UIView和CALayer的选择

使用 UIView 或 CALayer 绘制和动画?

iOS 中 UIView 和 CALayer 的关系

无法让 CALayer 在 UIView 中显示

UIView和CALayer