【发布时间】:2012-05-28 22:26:14
【问题描述】:
我不太明白 CALayer 的 display 和 drawInContext 与视图中的 drawRect 有何关系。
如果我有一个每 1 秒设置一次 [self.view setNeedsDisplay] 的 NSTimer,则每 1 秒调用一次 drawRect,如 drawRect 内的 NSLog 语句所示。
但是,如果我将 CALayer 子类化并将其用于视图,如果我将 display 方法设为空,那么现在 drawRect 将永远不会被调用。 更新:但display 每 1 秒调用一次,如 NSLog 语句所示。
如果我删除那个空的display 方法并添加一个空的drawInContext 方法,那么drawRect 将永远不会被调用。 更新:但drawInContext 每 1 秒调用一次,如 NSLog 语句所示。
究竟发生了什么?似乎display 可以选择性地调用drawInContext 而drawInContext 可以选择性地调用drawRect(如何?),但这里的真实情况是什么?
更新:答案有更多线索:
我将CoolLayer.m 代码更改为以下内容:
-(void) display {
NSLog(@"In CoolLayer's display method");
[super display];
}
-(void) drawInContext:(CGContextRef)ctx {
NSLog(@"In CoolLayer's drawInContext method");
[super drawInContext:ctx];
}
所以,假设在 View 的位置 (100,100) 有一个月亮(由 Core Graphics 绘制的圆圈),现在我将其更改为位置 (200,200),自然会调用 [self.view setNeedsDisplay] ,现在,CALayer 将完全没有缓存新视图图像,因为我的drawRect 指示现在应该如何显示月亮。
即便如此,入口点是CALayer的display,然后是CALayer的drawInContext:如果我在drawRect设置断点,调用堆栈显示:
所以我们可以看到先进入CoolLayer的display,然后进入CALayer的display,然后是CoolLayer的drawInContext,然后是CALayer的drawInContext,即使在这种情况下,没有这样的缓存存在新图像。
最后,CALayer 的drawInContext 调用代理的drawLayer:InContext。委托是视图(FooView 或 UIView)...drawLayer:InContext 是 UIView 中的默认实现(因为我没有覆盖它)。终于drawLayer:InContext调用drawRect了。
所以我猜测两点:为什么即使没有图像缓存,它也会进入CALayer?因为通过这种机制,图像是在上下文中绘制的,最后返回display,CGImage就是从这个上下文中创建出来的,然后现在设置为缓存的新图像。这就是 CALayer 缓存图像的方式。
我不太确定的另一件事是:如果[self.view setNeedsDisplay] 总是触发drawRect 被调用,那么什么时候可以使用CALayer 中的缓存图像?可能是......在Mac OS X上,当另一个窗口覆盖一个窗口时,现在顶部窗口被移开。现在我们不需要调用drawRect 来重绘所有内容,而是可以使用CALayer 中的缓存图像。或者在 iOS 上,如果我们停止应用程序,执行其他操作,然后返回应用程序,则可以使用缓存的图像,而不是调用 drawRect。但是如何区分这两种“脏”呢?一个是“未知脏”——月亮需要按照drawRect 逻辑的要求重新绘制(它也可以使用随机数作为坐标)。其他类型的脏是被掩盖或消失,现在需要重新显示。
【问题讨论】:
标签: ios uiview core-animation calayer drawrect