2

我正在处理 Core Graphic 中的一些东西,我正在寻找关于几个主题的额外说明。

drawRect:我对此有所了解,并且知道这是 UIView 的所有绘图方面的所在,但我不清楚幕后发生了什么。当我创建一个 UIView 并填写 drawRect 然后将另一个对象的 UIView 设置为该自定义视图时会发生什么?什么时候调用drawRect?

CGGraphicsContext:我知道这样做的目的是什么并且理解这个概念,但我无法确切地看到它是如何工作的。例如:

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

上面的代码在我的应用程序中并且工作正常。让我感到困惑的是它是如何工作的。保存/恢复上下文的想法是有道理的,但看起来我实际上是在保存一个上下文,使用完全相同的上下文进行更改,然后再次恢复相同的上下文。好像我正在保存一个上下文,然后在该上下文之上编写,只是为了恢复它。它是如何被保存到当你恢复它时,它是一个不同于刚刚用于进行更改的上下文实例?您在每种情况下都使用相同的变量上下文引用。

最后,我会感谢任何关于使用 Core Graphics 的实践项目或示例的资源。我正在寻求提高我在这方面的技能,因为我目前显然没有太多东西。

4

4 回答 4

3

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

将视图添加到“实时”视图图形会将视图的框架标记为需要显示。然后主运行循环创建并合并无效的矩形,并很快返回调用绘图。它不会在失效后立即绘制。这是一件好事,因为例如调整大小会导致严重的过度绘制——多余的工作会扼杀许多应用程序的绘图性能。绘制时,会创建一个上下文来渲染——最终输出到它的目的地。

图形上下文是可以自由地为其目的地优化工作的抽象——目的地可以是设备/屏幕、位图、PDF等。但是,上下文句柄CGContextRef(它的状态(这些参数都记录在这里)。这些参数集的操作类似于堆栈:Push = CGContextSaveGState、Pop = CGContextRestoreGState。尽管上下文指针没有改变,但参数集的堆栈正在改变。

至于资源,请参阅使用 Quartz 编程。它现在已经 8 岁了,最初是为 OS X 编写的——但这最终并不重要,因为绘图系统和 API 的基础从那时起实际上并没有显着发展——这就是你想要的专注在。API 已被扩展,因此最好回顾一下自 10.4 以来引入了哪些 API,看看它们解决了哪些问题,但这对您来说暗中是一件好事,因为它有助于保持对绘图系统基本操作的关注。请注意,iOS 中排除了某些功能(例如,我认为通常是由于浮点性能和内存限制),因此每个示例可能无法在 iOS 上使用,但我知道没有更好的指南。

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

于 2013-08-30T00:02:49.897 回答
2

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

保存图形状态会将当前图形状态推送到堆栈上。图形状态包含填充和描边设置、当前变换矩阵等。有关详细信息,请参阅Apple 的文档

Quartz 2D Programming Guide不包含很多示例,但在其他方面非常全面。

于 2013-08-29T23:41:25.897 回答
0

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

保存状态让您保存所有这些参数以供以后将重用它们的绘图命令。

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

恢复状态可以让您回到原来的位置。

我推荐这本书在 Mac OS X 中使用 Quartz 2D 和 PDF 图形编程

虽然在某些方面有点过时,但它真的会教你石英/核心图形是如何真正流动的。

于 2013-08-30T00:06:21.560 回答
0

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

首先有屏上绘图和离屏绘图的概念。屏幕上的绘图在 GPU 中进行,而屏幕外的绘图在 CPU 中进行以绘制事物,然后将其交给 GPU 以在屏幕上显示。这就是 drawRect() 出现的地方(drawrect 只是做屏幕外绘图的一种方式)。这就是为什么在 drawRect 模板方法中(你会在创建 UIView 的子类时看到)中有一条 Apple 的评论告诉

“仅覆盖 drawRect:如果您执行自定义绘图。空实现会对动画期间的性能产生不利影响”

原因是每当有 drawRect 方法时,iOS 必须要求 CPU 处理 drawRect 中发生的绘图并将其交给 GPU。(不要认为这是一件坏事:))。这就是在抽象级别的 drawRect 中发生的事情。

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

考虑这样的事情。假设您在一个矩形上绘图,您必须将绘图的下一部分限制在它的右半边,并使用阴影和抗锯齿等。您可以在绘制右侧之前保存您的上下文并设置您想要的任何属性完成此操作后,您可以简单地恢复上下文,并且可以继续使用之前的所有设置,而无需再次明确设置它们。当您绘制复杂的图纸时,这也是一种很好的做法,否则它会产生您可能无法预料的奇怪结果。下面是这样的

- 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);
}

现在,您在第 1 部分中设置的任何属性都不会影响第 2 部分和第 3 部分的绘图,依此类推。

希望这可以帮助,

于 2013-08-30T00:40:58.200 回答