drawRect总是希望在缩小视图时更新整个屏幕

时间:2012-06-22 16:58:00

标签: ios uiscrollview drawrect cgcontextdrawimage

我有一个CGImage,显示在由UIScrollView控制的UIView中。图像通常是1680 * 1050,24位颜色,没有alpha通道。

图像的创建方式如下:

CGImageRef bitmapClass::CreateBitmap(int width, int height, int imageSize, int colorDepth, int bytesPerRow)
{
   unsigned char* m_pvBits = malloc(imageSize);

   // Initializt bitmap buffer to black (red, green, blue)
   memset(m_pvBits, 0, imageSize);

   m_DataProviderRef = 
      CGDataProviderCreateWithData(NULL, m_pvBits, imageSize, NULL); 

   m_ColorSpaceRef = 
      CGColorSpaceCreateDeviceRGB();   

   return
      CGImageCreate(width, height, 
                    8, //kBitsPerComponent 
                    colorDepth, 
                    bytesPerRow, 
                    m_ColorSpaceRef, 
                    kCGBitmapByteOrderDefault | kCGImageAlphaNone, 
                    m_DataProviderRef, 
                    NULL, false, kCGRenderingIntentDefault);
}

通过更改m_pvBits中的像素并使用以下内容在UIView中更新,在后台定期更新图像内容:

[myView setNeedsDisplayInRect:rect];

调用drawRect,显示如下图像:

- (void)drawRect:(CGRect)rect
{
   CGRect imageRect;
   imageRect.origin = CGPointMake(0.0, 0.0);
   imageRect.size = CGSizeMake(self.imageWidth, self.imageHeight);

   CGContextRef context = UIGraphicsGetCurrentContext();

   CGContextSetInterpolationQuality(context, kCGInterpolationNone);

   // Drawing code
   CGContextDrawImage(context, imageRect, (CGImageRef)pWindow->GetImageRef());
}

只要视图没有缩小(缩小),这就可以正常工作。我知道'rect'实际上并没有直接在drawRect中使用,但'context'似乎知道CGContextDrawImage应该更新的屏幕部分。

我的问题是,即使我只使用setNeedsDisplayInRect使屏幕的一小部分区域无效,当视图缩小时,整个屏幕也会调用drawRect。因此,如果我的图像是1680 * 1050并且我使一个小矩形(x,y,w,h)=(512,640,32,32)无效,则使用(x,y,w,h)=(0)调用drawRect ,0,1680,1050)。

为什么?

2 个答案:

答案 0 :(得分:3)

Apple提供的一个有趣的示例代码项目可能会对您有所帮助。它被称为Large Image Downsizing。它做了很多事情,但真正有趣的部分是TiledImageView.m。其中,视图的图层类设置为CATiledLayer

+ (Cl ass)layerClass {
    return [CATiledLayer class];
}

使用init方法设置了tilesLayer属性:

// Create a new TiledImageView with the desired frame and scale.
-(id)initWithFrame:(CGRect)_frame image:(UIImage*)_image scale:(CGFloat)_scale {
    if ((self = [super initWithFrame:_frame])) {
        self.image = _image;
        imageRect = CGRectMake(0.0f, 0.0f, CGImageGetWidth(image.CGImage), CGImageGetHeight(image.CGImage));
        imageScale = _scale;
        CATiledLayer *tiledLayer = (CATiledLayer *)[self layer];
        // levelsOfDetail and levelsOfDetailBias determine how
        // the layer is rendered at different zoom levels.  This
        // only matters while the view is zooming, since once the 
        // the view is done zooming a new TiledImageView is created
        // at the correct size and scale.
        tiledLayer.levelsOfDetail = 4;
        tiledLayer.levelsOfDetailBias = 4;
        tiledLayer.tileSize = CGSizeMake(512.0, 512.0); 
    }
    return self;
}

最后,这是非常有趣的部分,这是drawRect:实现(NSLog来自我):

-(void)drawRect:(CGRect)_rect {
    CGContextRef context = UIGraphicsGetCurrentContext();    
    CGContextSaveGState(context);
    // Scale the context so that the image is rendered 
    // at the correct size for the zoom level.
    CGContextScaleCTM(context, imageScale,imageScale);  
    NSLog(@"rect: %@, imageScale: %.4f, clip: %@", NSStringFromCGRect(_rect), imageScale, NSStringFromCGRect(CGContextGetClipBoundingBox(context)));
    CGContextDrawImage(context, imageRect, image.CGImage);
    CGContextRestoreGState(context);    
}
每个512x512磁贴都会调用

drawRect:。但是,传入的_rect并未在方法中使用。它不必,因为当前上下文的剪切路径设置为正确的区域(正如您将通过CGContextGetClipBoundingBox的输出看到的)。就像Rob说的那样,可以使用CGContextDrawImage,只会绘制大图像的请求“平铺”,尽管看起来好像整个图像一次又一次地被绘制。如果您不使用CATiledLayer,则会一次又一次地绘制整个图像,从而减慢所有内容的速度。但是当你使用CATiledLayer时,只会绘制当前需要的“图块”,这会让它更快。

我希望这会有所帮助。

答案 1 :(得分:1)

谢谢你的回答。

我观察到传递给drawRect的rect参数的内容与我查询CGContextGetClipBoundingBox()时得到的内容相同。

你建议我应该将我的绘图优化到剪切边界 - 但是我在这里没有做任何计算。我只是在调用CGContextDrawImage()。我可以看到其他程序员抱怨CGContextDrawImage性能不佳,而且从iPhone 3到4显然慢得多。我当然希望性能更好但是现在最大的问题是iOS更新整个图像即使只是一小部分无效(使用setNeedsDisplay)。

通过缩小我的意思是我能够看到更多的图像,但图像缩小了。我不是一直在放大和缩小,但是图像的一小部分会定期更新并调用setNeedsDisplay。当我缩放或平移时它非常缓慢且突然,因为整个屏幕由iOS设置以进行更新。

你是对的,CGContextDrawImage优化实际绘制的内容 - 我可以通过测量操作所需的时间来看到它。

正如您所看到的,我使用malloc分配了我的图像位。还有另一种方法可以分配更好地优化图形处理器的图像位吗?

CGImageCreate是否有更优化的ColorRef模式或其他标志?