使用drawRect中的Core Graphics绘制图像网格:

时间:2009-04-17 20:22:56

标签: iphone objective-c core-animation core-graphics

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

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是用户触摸屏幕的CGPoints。所以我基本上在用户触摸的网格上显示不同的图像。

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

无论如何,我开始研究CoreAnimation和Quartz文档,并且真的很困惑。我不确定我是否应该为每个砖块创建多个UIViews(似乎过多),或者是CALayers或CGLayers的网格......我认为这很简单,我想做什么......但我真的不明白图层,以及使用CALayer和CGLayer之间的区别。显然“所有UIViews都是层支持的”这是什么意思?

我对如何实现这一点感到很遗憾。我基本上想要在网格中交换图像,这样用户就可以在屏幕上“画画”并切换图像。


修改

我尝试使用[self setNeedsDisplayinRect]实现此功能,并传入用户手指下的CGRect。然而,这仍然是在TouchesMoved中调用DrawRect,它给了我想要的效果,但在iPhone上却太慢了。使用CALayers是否有更有效的方法来实现相同的效果?我是Core Animation的新手,并不真正了解如何使用图层来解决这个问题。

3 个答案:

答案 0 :(得分:2)

我认为在你的情况下,UIImage应该处理这个应用程序并提供良好的性能。问题似乎是您强制整个屏幕重绘以响应每条drawRect:消息。传入的rect指定了您需要重绘的“脏区域”。任何其他绘图只是浪费时间。

同样,传递给视图的setNeedsDisplay:的矩形是您特别想要失效的矩形。计算触摸周围的矩形并使其无效。 UIKit将(可能)联合多个脏的rects并发送一个drawRect:

我建议你执行以下优化:

  1. 检查传递给drawRect:(在调试器中)的脏矩形,如果它小于全屏编写代码,以确保只在脏矩形内重新绘制图像
  2. 使用touches事件确保仅使需要重绘的区域无效,然后重新访问1.
  3. 如果这不能达到你所需要的性能,可以使用Quartz来绘制黑白图像,而不是使用图像,因为这是一些UIImage怪异(但我怀疑是这种情况)
  4. 如果需要显示位图和1&amp; 2无法获得所需的性能,您将不得不求助于更低级别的技术。在SO上有很多例子包括this question

答案 1 :(得分:1)

要仅使视图的一部分无效,请仅使用已更改的区域调用setNeedsDisplayInRect:。如果多个rects已更改,您可以使用不同的rects调用它两次。

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

此外,您不应该直接致电drawRect:,而是使用setNeedsDisplay。只要视图区域无效并且需要绘画,UIKit就会调用drawRect:

答案 2 :(得分:1)

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

这样,重新渲染的显示器的唯一部分将是正在改变的特定UIView。我推荐UIViews优于CALayers只是因为UIViews在视图层次结构中更容易放置。

为了清楚解释CALayers,UIViews等在iPhone上的交互方式,我建议您阅读“iPhone应用程序编程指南”的“视图架构和几何”部分中的“视图渲染架构”小节”