4

对我之前的结果不满意,我被要求创建一个在缩放时不会模糊的手绘视图。我能想象到的唯一方法是使用 a CATiledLayer,否则在缩放时画线太慢了。目前,我已经设置好它每次都会重绘每一行,但我想知道我是否可以在上下文或其他东西中缓存前几行的结果(而不是像素,因为它们需要很好地缩放)。

我考虑过 CGBitmapContext,但这是否意味着我需要在每次缩放后拆除并设置一个新的上下文?问题是在 Retina 显示器上,线条绘制太慢(在 iPad 2 上是马马虎虎),尤其是在缩放时绘制。App Store 中有一个叫 GoodNotes 的应用程序,它精美地证明了这是可能的,并且可以顺利完成,但我无法理解他们是如何做到的。到目前为止,这是我的代码(今天大部分时间的结果):

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

    CGContextSetLineWidth(c, mLineWidth);
    CGContextSetAllowsAntialiasing(c, true);
    CGContextSetShouldAntialias(c, true);
    CGContextSetLineCap(c, kCGLineCapRound);
    CGContextSetLineJoin(c, kCGLineJoinRound);

    //Protect the local variables against the multithreaded nature of CATiledLayer
    [mLock lock]; 
    NSArray *pathsCopy = [mStrokes copy];
    for(UIBezierPath *path in pathsCopy) //**Would like to cache these**
    {
        CGContextAddPath(c, path.CGPath);
        CGContextStrokePath(c);
    }
    if(mCurPath)
    {
        CGContextAddPath(c, mCurPath.CGPath);
        CGContextStrokePath(c);
    }

    CGRect pathBounds = mCurPath.bounds;
    if(pathBounds.size.width > 32 || pathBounds.size.height > 32)
    {
        [mStrokes addObject:mCurPath];
        mCurPath = [[UIBezierPath alloc] init];
    }
   [mLock unlock];
}

分析显示迄今为止最热门的功能是GCSFillDRAM8by1

4

2 回答 2

1

首先,由于路径描边是最昂贵的操作,您不应该锁定它,因为这会阻止您在不同的核心上同时绘制图块。

其次,我认为您可以通过在上下文中添加所有路径并完全抚摸它们来避免CGContextStrokePath多次调用。

[mLock lock]; 
for ( UIBezierPath *path in mStrokes ) {
    CGContextAddPath(c, path.CGPath);
}
if ( mCurPath ) {
    CGContextAddPath(c, mCurPath.CGPath);
}
CGRect pathBounds = mCurPath.bounds;
if ( pathBounds.size.width > 32 || pathBounds.size.height > 32 )
{
    [mStrokes addObject:mCurPath];
    mCurPath = [[UIBezierPath alloc] init];
}
[mLock unlock];
CGContextStrokePath(c);

CGContextRef只是进行绘图操作的画布。您无法缓存它,但您可以使用CGImageRef路径的平面位图图像创建一个并重用该图像。这对缩放没有帮助(因为当细节级别发生变化时,您需要重新创建图像),但在用户绘制非常长的路径时有助于提高性能。

关于该主题有一个非常有趣的 WWDC 2012 会议视频:优化 2D 图形和动画性能

于 2012-08-08T08:34:25.377 回答
1

The bottleneck was actually the way I was using CATiledLayer. I guess it is too much to update with freehand info. I set it up with levels of detail as I saw in the docs and tutorials online, but in the end I didn't need that much. I just hooked up the scrollview delegate, cleared the contents when it was done zooming and changed the contentScale of the layer to match the scroll view. The result was beautiful (it disappears and fades back in, but that can't be helped).

于 2012-08-08T11:48:40.763 回答