繁体   English   中英

在UIView(iPhone)中逐步绘制

[英]Drawing incrementally in a UIView (iPhone)

据我所知,到目前为止,每次我在drawRect:UIView中绘制一些内容时,整个上下文都会被删除然后重新绘制。

所以我必须做这样的事情来绘制一系列点:

方法A:在每次通话时绘制所有内容

- (void)drawRect:(CGRect)rect { 

    CGContextRef context = UIGraphicsGetCurrentContext();

    CGContextDrawImage(context, self.bounds, maskRef);      //draw the mask
    CGContextClipToMask(context, self.bounds, maskRef);     //respect alpha mask
    CGContextSetBlendMode(context, kCGBlendModeColorBurn);  //set blending mode

    for (Drop *drop in myPoints) {
        CGContextAddEllipseInRect(context, CGRectMake(drop.point.x - drop.size/2, drop.point.y - drop.size/2, drop.size, drop.size));
    }

    CGContextSetRGBFillColor(context, 0.5, 0.0, 0.0, 0.8);
    CGContextFillPath(context);
}

这意味着,每次我想添加一个新的时候,我必须存储我所有的Dots(没关系),然后逐个重新绘制它们。 不幸的是,这给了我糟糕的表现,我相信还有其他方法可以做到这一点,效率更高。

编辑:使用MrMage的代码,我做了以下,不幸的是,它同样慢,颜色混合不起作用。 我可以尝试其他任何方法吗?

方法B:保存UIImage中的先前绘制并仅绘制新内容和此图像

- (void)drawRect:(CGRect)rect
{
    //draw on top of the previous stuff
    UIGraphicsBeginImageContext(self.frame.size);
    CGContextRef ctx = UIGraphicsGetCurrentContext(); // ctx is now the image's context
    [cachedImage drawAtPoint:CGPointZero];
    if ([myPoints count] > 0)
    {
        Drop *drop = [myPoints objectAtIndex:[myPoints count]-1];
        CGContextClipToMask(ctx, self.bounds, maskRef);         //respect alpha mask
        CGContextAddEllipseInRect(ctx, CGRectMake(drop.point.x - drop.dropSize/2, drop.point.y - drop.dropSize/2, drop.dropSize, drop.dropSize));
        CGContextSetRGBFillColor(ctx, 0.5, 0.0, 0.0, 1.0);
        CGContextFillPath(ctx);
    }
    [cachedImage release];
    cachedImage = [UIGraphicsGetImageFromCurrentImageContext() retain];
    UIGraphicsEndImageContext();

    //draw on the current context   
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextDrawImage(context, self.bounds, maskRef);          //draw the mask
    CGContextSetBlendMode(context, kCGBlendModeColorBurn);      //set blending mode
    [cachedImage drawAtPoint:CGPointZero];                      //draw the cached image
}

编辑:毕竟我结合下面提到的方法之一与仅在新的rect重绘。 结果是: 快速方法:

- (void)addDotAt:(CGPoint)point
{
    if ([myPoints count] < kMaxPoints) {
        Drop *drop = [[[Drop alloc] init] autorelease];
        drop.point = point;
        [myPoints addObject:drop];
        [self setNeedsDisplayInRect:CGRectMake(drop.point.x - drop.dropSize/2, drop.point.y - drop.dropSize/2, drop.dropSize, drop.dropSize)];      //redraw
    }
}

- (void)drawRect:(CGRect)rect
{
    CGContextRef context = UIGraphicsGetCurrentContext();

    CGContextDrawImage(context, self.bounds, maskRef);                                              //draw the mask
    CGContextClipToMask(context, self.bounds, maskRef);                                             //respect alpha mask
    CGContextSetBlendMode(context, kCGBlendModeColorBurn);                                          //set blending mode

    if ([myPoints count] > 0)
    {
        Drop *drop = [myPoints objectAtIndex:[myPoints count]-1];
        CGPathAddEllipseInRect (dotsPath, NULL, CGRectMake(drop.point.x - drop.dropSize/2, drop.point.y - drop.dropSize/2, drop.dropSize, drop.dropSize));
    }
    CGContextAddPath(context, dotsPath);

    CGContextSetRGBFillColor(context, 0.5, 0.0, 0.0, 1.0);
    CGContextFillPath(context);
}

感谢大家!

如果您每次绘制时实际上只更改了UIView内容的一小部分(并且其余内容通常保持不变),则可以使用此方法。 不是每次都重绘UIView的所有内容,而是只使用-[UIView setNeedsDisplayInRect:]而不是-[UIView setNeedsDisplay]来标记需要重绘的视图区域。 您还需要确保在绘制之前不通过设置view.clearsContextBeforeDrawing = YES;清除图形内容view.clearsContextBeforeDrawing = YES;

当然,所有这些也意味着你的drawRect:实现需要尊重rect参数,然后该参数应该是整个视图的rect的一小部分(除非其他东西弄脏整个矩形),并且只绘制该部分。

您可以将CGPath保存为班级成员。 并且在绘制方法中使用它,您只需要在点改变时创建路径,但不是每次重绘视图时创建路径,如果点是增量的,只需继续将椭圆添加到路径中。 在drawRect方法中,您只需要添加路径

CGContextAddPath(context,dotsPath);

-(CGMutablePathRef)createPath
{
    CGMutablePathRef dotsPath =  CGPathCreateMutable();

    for (Drop *drop in myPoints) {
        CGPathAddEllipseInRect ( dotsPath,NULL,
            CGRectMake(drop.point.x - drop.size/2, drop.point.y - drop.size/2, drop.size, drop.size));
    }

return dotsPath;
}

如果我正确理解你的问题,我会尝试直接绘制到CGBitmapContext而不是屏幕。 然后在drawRect ,仅绘制rect参数中必需的预渲染位图部分。

你要绘制多少个椭圆? 通常,Core Graphics应该能够快速绘制很多省略号。

但是,您可以将旧图形缓存到图像中(但我不知道此解决方案是否更具性能):

UIGraphicsBeginImageContext(self.frame.size);
CGContextRef ctx = UIGraphicsGetCurrentContext(); // ctx is now the image's context

[cachedImage drawAtPoint:CGPointZero];
// only plot new ellipses here...

[cachedImage release];
cachedImage = [UIGraphicsGetImageFromCurrentImageContext() retain];
UIGraphicsEndImageContext();

CGContextRef context = UIGraphicsGetCurrentContext();

CGContextDrawImage(context, self.bounds, maskRef);          //draw the mask
CGContextClipToMask(context, self.bounds, maskRef);         //respect alpha mask
CGContextSetBlendMode(context, kCGBlendModeColorBurn);      //set blending mode

[cachedImage drawAtPoint:CGPointZero];

如果您能够将图形缓存为图像,则可以利用UIView的CoreAnimation支持。 这将比使用Quartz快得多,因为Quartz在软件中绘图。

- (CGImageRef)cachedImage {
    /// Draw to an image, return that
}
- (void)refreshCache {
    myView.layer.contents = [self cachedImage];
}
- (void)actionThatChangesWhatNeedsToBeDrawn {
    [self refreshCache];
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM