UIView:如何进行无损绘制?

发布于 2024-07-20 09:50:28 字数 1784 浏览 6 评论 0原文

我原来的问题:

我正在创建一个简单的绘图 应用程序并且需要能够 在我的 drawRect 中绘制现有的、先前绘制的内容。 在现有内容之上绘制的正确方法是什么 而不完全替换它?

根据此处和其他地方收到的答案,交易如下。

  1. 您应该准备好重新绘制 每当drawRect时整个矩形 叫做。

  2. 无法通过执行以下操作来阻止内容被删除:

    [self setClearsContextBeforeDrawing: NO];

    这只是对图形引擎的一个提示,让它为您预先清除视图是没有意义的,因为无论如何您可能都需要重新绘制整个区域。 它可能会阻止您的视图被自动删除,但您不能依赖它

  3. 要在视图顶部绘制而不擦除,请在离屏位图上下文中进行绘制(系统永远不会清除该上下文)。然后在您的 drawRect 中,从此离屏复制屏幕缓冲区到视图。

示例:

- (id) initWithCoder: (NSCoder*) coder {    
     if (self = [super initWithCoder: coder]) {
         self.backgroundColor = [UIColor clearColor];
         CGSize size = self.frame.size;
         drawingContext = [self createDrawingBufferContext: size];
     }

     return self;
 }

- (CGContextRef) createOffscreenContext: (CGSize) size  {
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    CGContextRef context = CGBitmapContextCreate(NULL, size.width, size.height, 8, size.width*4, colorSpace, kCGImageAlphaPremultipliedLast);
    CGColorSpaceRelease(colorSpace);

    CGContextTranslateCTM(context, 0, size.height);
    CGContextScaleCTM(context, 1.0, -1.0);
    return context;
}


- (void)drawRect:(CGRect) rect {    
    UIGraphicsPushContext(drawingContext);
    CGImageRef cgImage = CGBitmapContextCreateImage(drawingContext); 
    UIImage *uiImage = [[UIImage alloc] initWithCGImage:cgImage];
    UIGraphicsPopContext();
    CGImageRelease(cgImage);
    [uiImage drawInRect: rect];
    [uiImage release];
 }

TODO:任何人都可以优化 drawRect 以便仅将(通常很小的)修改后的矩形区域用于副本吗?

My original question:

I'm creating a simple drawing
application and need to be able to
draw over existing, previously drawn content in my drawRect.
What is the proper way to draw on top of existing content
without entirely replacing it?

Based on answers received here and elsewhere, here is the deal.

  1. You should be prepared to redraw the
    entire rectangle whenever drawRect
    is called.

  2. You cannot prevent the contents from being erased by doing the following:

    [self setClearsContextBeforeDrawing: NO];

    This is merely a hint to the graphics engine that there is no point in having it pre-clear the view for you, since you will likely need to re-draw the whole area anyway. It may prevent your view from being automatically erased, but you cannot depend on it.

  3. To draw on top of your view without erasing, do your drawing to an off-screen bitmap context (which is never cleared by the system.) Then in your drawRect, copy from this off-screen buffer to the view.

Example:

- (id) initWithCoder: (NSCoder*) coder {    
     if (self = [super initWithCoder: coder]) {
         self.backgroundColor = [UIColor clearColor];
         CGSize size = self.frame.size;
         drawingContext = [self createDrawingBufferContext: size];
     }

     return self;
 }

- (CGContextRef) createOffscreenContext: (CGSize) size  {
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    CGContextRef context = CGBitmapContextCreate(NULL, size.width, size.height, 8, size.width*4, colorSpace, kCGImageAlphaPremultipliedLast);
    CGColorSpaceRelease(colorSpace);

    CGContextTranslateCTM(context, 0, size.height);
    CGContextScaleCTM(context, 1.0, -1.0);
    return context;
}


- (void)drawRect:(CGRect) rect {    
    UIGraphicsPushContext(drawingContext);
    CGImageRef cgImage = CGBitmapContextCreateImage(drawingContext); 
    UIImage *uiImage = [[UIImage alloc] initWithCGImage:cgImage];
    UIGraphicsPopContext();
    CGImageRelease(cgImage);
    [uiImage drawInRect: rect];
    [uiImage release];
 }

TODO: can anyone optimize the drawRect so that only the (usually tiny) modified rectangle region is used for the copy?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

や莫失莫忘 2024-07-27 09:50:28

在屏幕外图像中绘制所有内容并在绘制屏幕时简单地显示该图像是相当常见的。 您可以阅读: 创建位图图形上下文

It is fairly common to draw everything in an offscreen image, and simply display this image when drawing the screen. You can read: Creating a Bitmap Graphics Context.

无所谓啦 2024-07-27 09:50:28

优化drawRect

试试这个:

- (void)drawRect:(CGRect)rect {
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGImageRef cgImage = CGBitmapContextCreateImage(drawingContext);
    CGContextClipToRect(context, rect);
    CGContextDrawImage(context, CGRectMake(0, 0, self.frame.size.width, self.frame.size.height), cgImage);
    CGImageRelease(cgImage);
}

之后你还应该在代码中注释这些行:

//CGContextTranslateCTM(context, 0, size.height);
//CGContextScaleCTM(context, 1.0, -1.0);

还创建了一个单独的问题,以确保这是最佳方式。

On optimizing drawRect

Try this:

- (void)drawRect:(CGRect)rect {
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGImageRef cgImage = CGBitmapContextCreateImage(drawingContext);
    CGContextClipToRect(context, rect);
    CGContextDrawImage(context, CGRectMake(0, 0, self.frame.size.width, self.frame.size.height), cgImage);
    CGImageRelease(cgImage);
}

After that you should also comment these lines in your code:

//CGContextTranslateCTM(context, 0, size.height);
//CGContextScaleCTM(context, 1.0, -1.0);

Also created a separate question to be sure that it's the optimal way.

不离久伴 2024-07-27 09:50:28

这似乎是比我一直使用的更好的方法。 也就是说,在触摸事件中,我复制了即将更新的视图。 然后在 drawRect 中,我获取该图像并将其绘制到视图中,并同时更改其他视图。

但这似乎效率低下,但却是我想出的唯一方法。

This seems like a better method than I've been using. That is, in a touches event I make a copy of the view about to be updated. Then in drawRect I take that image and draw it to the view and make my other view changes at the same time.

But this seems inefficient but the only way I figured out how to do it.

迷途知返 2024-07-27 09:50:28

这可以防止您的视图在完成drawRect之前被擦除:

[self.layer setNeedsDisplay];

另外,我发现最好在drawRect方法中完成所有绘图(除非您有充分的理由不这样做)。 与简单地绘制一次所有内容相比,在屏幕外绘制和传输需要更多时间并增加更多复杂性。

This prevents your view from being erased before drawRect is done:

[self.layer setNeedsDisplay];

Also, I find it is better to do all the drawing in the drawRect method (unless you have a good reason not to). Drawing offscreen and transferring takes more time and adds more complexity then simply drawing everything once.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文