drawRect和CGGraphicsContext如何工作?

我在Core Graphic的一些工作,我正在寻找一些关于几个主题的额外澄清。

drawRect:我已经理解了这一点,知道它是UIView所有绘图方面的内容,但是我不清楚这个场景背后发生了什么。 当我创build一个UIView并填写drawRect,然后将另一个对象的UIView设置为该自定义视图时会发生什么? drawRect何时被调用?

CGGraphicsContext:我知道这是什么目的,并理解这个概念,但是我看不出它是如何工作的。 例如:

CGContextSaveGState(context); CGContextAddRect(context, rect); CGContextClip(context); CGContextDrawLinearGradient(context, gradient, startPoint, endPoint, 0); CGContextRestoreGState(context); 

上面的代码在我的应用程序和工作是正确的。 让我困惑的是它是如何工作的。 保存/恢复上下文的想法是有道理的,但是看起来像我从字面上保存上下文,使用完全相同的上下文来进行更改,然后再次恢复相同的上下文。 这看起来像是我正在保存一个上下文,然后写在上下文的顶部,只是为了恢复它。 如何将它保存到恢复它的位置,这与刚刚用于进行更改的环境是不同的实例? 在任何情况下,都使用相同的variables上下文的引用。

最后,我将不胜感激任何资源的实践项目或使用核心graphics的例子。 我希望提高我在这个问题上的技巧,因为我目前显然没有太多。

当我创build一个UIView并填写drawRect,然后将另一个对象的UIView设置为该自定义视图时会发生什么? drawRect何时被调用?

将视图添加到“实时”视图graphics标记视图的框架需要显示。 主运行循环然后创build并合并无效的矩形,并很快返回到调用绘图。 它不会立即失效。 这是一件好事,因为例如resize会导致显着的透支 – 冗余的工作,这将会杀死很多应用程序的绘图性能。 绘图时,会创build一个上下文以渲染到 – 最终输出到目标。

graphics上下文是抽象的,它们可以自由地针对其目的地进行优化 – 目标可以是设备/屏幕,位图,PDF等。然而,上下文句柄( CGContextRef )本身引用目的地并且保存一组参数关于它的状态( 这些参数都logging在这里 )。 这些参数集像堆栈一样操作:Push = CGContextSaveGState ,Pop = CGContextRestoreGState 。 尽pipe上下文指针没有改变,但参数集的堆栈正在改变。

至于资源,请参阅使用Quartz编程 。 它现在已经8岁了,最初是为OS X编写的 – 但最终并不重要,因为从那时起,绘图系统和API的基本原理并没有发生重大的变化 – 这就是你打算的专注在。 这些API已经被扩展了,所以从10.4开始查看引入的API是很好的,看看他们解决了什么问题,但这对你来说是一件好事,因为它有助于把重点放在绘图系统的基本操作上。 请注意,iOS中排除了一些function(例如,由于浮点性能和内存限制,我认为),所以每个示例在iOS上可能不可用,但我知道没有更好的指导。

提示:如果使用Quartz而不是AppKit / UIKit,则可以在OS X和iOS上轻松地重用您的绘图代码。 此外,Quartz API的更新频率更低(即API往往寿命更长)。

-drawRect:在你(例如你的视图控制器)调用视图的方法-setNeedsDisplay或-setNeedsDisplayInRect:之后的某个时刻被调用。

保存graphics状态将当前graphics状态压入堆栈。 graphics状态包含填充和描边设置,当前的转换matrix等。有关详细信息,请参阅Apple的文档 。

“ Quartz 2D编程指南”不包含很多例子,但其他方面相当透彻。

对于石英/核心graphics,上下文实际上是一组当前参数,用于在上一张图纸上绘制下一个绘图命令。

保存状态让我们保存所有这些参数为以后的绘图命令,将重复使用它们。

然后你可以为一些绘图命令设置一组不同的参数。

恢复状态让你回到你所在的位置。

我推荐在Mac OS X中使用Quartz 2D和PDF Graphics进行编程

尽pipe在某些方面有点过时,但它会真正教会你如何真正stream动石英/核心graphics。

好吧,这是一个非常非常深刻的话题。 我会解释一些我理解的事情,并尽量保持简单。 如果我错了,我希望有人能纠正我。

首先是屏幕上绘图和屏外绘图的概念。 在屏幕上绘图是发生在GPU中,在CPU中进行离屏绘制绘制的东西,然后将其提供给GPU显示在屏幕上。 这就是drawRect()进入的地方(drawrect只是做屏幕外图纸的一种方法)。 这就是为什么在drawRect模板方法中(当你创buildUIView的一个子类的时候你会看到)有一个苹果说的评论

“只有重写drawRect:如果你执行自定义绘图,一个空的实现对animation性能有不利的影响”

原因是每当有drawRect方法的时候,iOS就不得不要求CPU把drawRect中发生的绘图保存下来并交给GPU。 (不要认为这是一件坏事:))。 所以这是在抽象层次上的drawRect中发生的事情。

现在到了为什么一遍又一遍地保存和恢复相同的上下文的问题。 你有没有尝试阅读关于保存/恢复上下文的苹果文档中的方法的描述? 如果你有,你会注意到它显示所有的graphics状态将受到这个影响。 好的,这有什么帮助?

考虑这样的事情。 比方说你正在绘制一个矩形,你必须限制右边一半的绘画的下一部分,并使用阴影和抗锯齿等。你可以保存你的上下文之前绘制右侧,并设置任何你想要的属性一旦你完成了,你可以简单地恢复上下文,你可以继续你以前的所有设置,而无需再次明确设置它们。 当你做复杂的绘图时,这是一个很好的做法,否则会产生不可预料的奇怪结果。 像下面这样的东西

 - drawRect() { CGContextSaveGState(context); drawLeftPart(); // - 1 drawRightPart(); // - 2 someOtherDrawing(); // - 3 CGContextRestoreGState(context); } - drawLeftPart() { CGContextSaveGState(context); // do your drawing CGContextRestoreGState(context); } - drawRightPart() { CGContextSaveGState(context); // do your drawing CGContextRestoreGState(context); } - someOtherDrawing() { CGContextSaveGState(context); // do your drawing CGContextRestoreGState(context); } 

现在你在第一部分设置的任何属性都不会影响第2和3部分的绘制。

希望这可以帮助,