在drawRect方法中使用Core Graphics绘制一个图像网格

5

我的问题是:我有一个简单的块状图像,我想把它制作成网格。我在我的UIView中创建了一个CGPoint数组。然后我使用

blackImage = [UIImage imageNamed:@"black.png"];

然后

- (void)drawRect:(CGRect)rect {
    for (int j = 0 ; j <= 11; j++)
    {
        for (int i = 0 ; i <= 7; i++) 
        {
            [blackImage drawAtPoint: (CGPointFromString([[self.points objectAtIndex:j] objectAtIndex:i]))];
        }
    }
    [whiteImage drawAtPoint:(CGPointMake((CGFloat)(floor((touchX+0.001)/40)*40), (CGFloat)(floor((touchY+0.001)/40))*40))];

    //  [whiteImage drawAtPoint:(CGPointMake(240.0, 320.0))];   
}

其中TouchX和TouchY是用户触摸屏幕的CGPoint。 所以我基本上在用户触摸的网格点上显示不同的图像。

首先,问题在于每次调用DrawRect时整个屏幕都会重新绘制。 我想能够保存状态(通过更改BOOL数组?),并让用户在屏幕上拖动并更改多个图像。 但是,当我在DrawRect之外时,无法使用UImage的“drawAtPoint”方法(会抛出错误)。

无论如何,我开始查看CoreAnimation和Quartz文档,并感到非常困惑。 我不确定是否应该为每个砖块创建多个UIView(似乎过度),还是一个CALayer或CGLayer的网格...我认为我想做的事情很简单...但我真的不理解Layers,以及使用CALayer和CGLayer之间的区别。 显然,“所有UIView都支持层”,这是什么意思?

我有点迷失在如何实现它的过程中。 我基本上想在网格中交换图像,以便用户可以在屏幕上“绘画”并切换图像。


编辑

我尝试使用[self setNeedsDisplayinRect]来实现此操作,并传递用户手指下的CGRect。 但是,这仍然在TouchesMoved中调用DrawRect,虽然这给我想要的效果,但在iPhone上太慢了。 有没有更有效的方法使用CALayers实现相同的效果? 我是Core Animation的新手,不太明白如何使用图层解决此问题。

3个回答

2
我认为在您的情况下,UIImage 应该处理这个应用程序并提供良好的性能。问题似乎是您在响应每个 drawRect: 消息时强制整个屏幕重新绘制。传递的矩形指定了您需要重新绘制的“脏区域”。任何其他绘图都只是浪费时间。
同样,您传递给视图的 setNeedsDisplay: 的矩形是您要使其无效的特定矩形。计算一个围绕触摸的矩形并使其无效。UIKit 将(可能)合并多个脏矩形并发送单个 drawRect:。
我建议您执行以下优化:
  1. 检查调试器中传递给您的 drawRect: 的脏矩形,并且如果它小于全屏,请编写代码确保您仅重新绘制脏矩形内的图像
  2. 使用 touches 事件确保您仅使需要重新绘制的区域无效,然后回到第1步。
  3. 如果这不能满足您的性能需求,请使用 Quartz 来绘制黑白矩形,而不是使用图像,以防止出现一些 UIImage 的怪异行为(但我怀疑这不是问题所在)
如果您需要显示位图,但1和2无法满足您的性能需求,您将不得不采用更低级别的技术。有很多例子可以参考,包括SO上的this question

1

如果只想使视图的一部分无效,可以调用setNeedsDisplayInRect:并传入改变的区域。如果多个矩形发生了变化,可以使用不同的矩形两次调用它。

另一种解决方法是创建多个CALayer并移动/隐藏它们。

此外,永远不要直接调用drawRect:,而应该使用setNeedsDisplay。每当视图的某个区域无效并需要绘制时,UIKit都会调用drawRect:


1

如果您的图像只有几个像素宽,那么77个离散图像作为CALayers或UIViews网格并不太繁重,因此我建议采用这种方法。 UIViews比CALayers稍微重一些,因此我会构建一个离散UIImageView的网格(假设您的黑色图像不仅仅是黑色,如果不是,您可以将标准UIView的backgroundColor设置为黑色或白色)。 如果您不需要跟踪触摸移动到视图上的位置,甚至可以通过UIImageView的自定义子类或控制器中的委托方法来处理切换视图图像的触摸处理。

这样,重新渲染的仅是正在更改的特定UIView部分。 我建议使用UIView而不是CALayer,仅仅是因为UIView在视图层次结构中放置起来稍微容易一些。

关于iPhone上CALayer、UIView等如何交互的清晰解释,我建议阅读“iPhone应用程序编程指南”中“视图架构和几何”部分中的“The View Rendering Architecture”子部分。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接