4

以前の結果に満足できなかったので、ズームしてもぼやけないフリーハンドの描画ビューを作成するように依頼されました。これが可能だと想像できる唯一の方法は、を使用する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

ボトルネックは、実際に私が CATiledLayer を使用していた方法でした。フリーハンドの情報で更新するには多すぎると思います。オンラインのドキュメントやチュートリアルで見たような詳細レベルでセットアップしましたが、最終的にはそれほど必要ありませんでした. スクロールビューデリゲートを接続し、ズームが完了したらコンテンツをクリアしcontentScale、スクロールビューに合わせてレイヤーを変更しました。結果はきれいでした(消えてフェードインしますが、それは仕方ありません)。

于 2012-08-08T11:48:40.763 に答える
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 セッション ビデオがあります: Optimizing 2D Graphics and Animation Performance

于 2012-08-08T08:34:25.377 に答える