2009-11-25 12 views
11

私が今まで理解していた限り、drawRect:にUIViewの何かを描画するたびに、全体のコンテキストが消去されてから再描画されます。UIView(iPhone)で段階的に描画する

は、だから私は一連のドットを描画するために、このような何かをする必要があります:

方法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); 
} 

上のすべてを描く、私はすべての私のドットを格納する必要が(それは問題ありません)、新しいものを追加するたびに、それらを1つ1つずつ再描画します。残念ながら、これは私のひどいパフォーマンスをもたらし、もっと効率的にこれを行う他の方法があると確信しています。

編集: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 
} 

EDIT新しいものと、この画像を描画:私は方法の一つが、中にのみ再描画して以下に言及して結合されたすべての後 を新しいrect。結果は次のとおりです。 FAST METHOD:

- (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); 
} 

みんなありがとう!

答えて

6

あなたが唯一の実際のごく一部を変更する場合描画するたびにUIViewのコンテンツ(残りのコンテンツは一般的に同じままです)を使用することができます。 UIViewのすべてのコンテンツを一度に再描画するのではなく、の代わりに-[UIView setNeedsDisplayInRect:]を使用して、再描画が必要なビューの領域のみをマークすることができます。 view.clearsContextBeforeDrawing = YES;

もちろん、これはまた、drawRect:の実装がrectパラメータを尊重する必要があることを意味します。これは、完全なものの小さなサブセクションである必要がありますビューのrect(他の何かがrect全体を汚していない限り)、その部分だけを描画します。

+0

"* view.clearsContextBeforeDrawing = NO; *"それは何をすべきドキュメントに記載しましたか?すべての図面はインクリメンタルでなければなりませんか?しかし、そうではありません。 – Dimitris

+1

drawRect:実装が更新されたセクションのみを描画することを確認しない限り、描画はインクリメンタルではありません。 "更新されたセクション"(ダーティセクション)をマークする標準的な方法は、setNeedsDisplayInRect:を使用しています。 clearsContentBeforeDrawing = NOを設定して、コンテンツ全体をコンテントで埋めると、パフォーマンスのメリットは小さくなります。 –

0

描画する楕円はいくつですか?一般に、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]; 
+0

私は(すべてののdrawRectに画像を描画:その上に楕円をマスキング)の約100 しかし、余分な作業をしましょう、多くを描いていないよそれも3GSにveeery遅くなります。 – Dimitris

+0

また、楕円を描いた後にマスクをかけることもできます(最初にバッファに描画し、バッファをマスクしてビューに描画することによって)。 – MrMage

+0

上記のコードでは、 "ctx"と言っていますが、 "context"を意味していますか?私は今あなたの方法を試して、違いがあるかどうかを見ています。 – Dimitris

2

CGPathをクラスのメンバーとして保存することができます。描画メソッドでは、ドットが変更されたときにパスを作成する必要がありますが、ビューが再描画されるたびにドットをインクリメンタルにするだけではなく、省略記号をパスに追加し続ける必要があります。 drawRectメソッドでは、私だけではなく、直接画面のCGBitmapContextに描画しようと、私が正しくあなたの問題を理解していれば、パスに

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; 
} 
+0

ちょうどそれも試みた。それは他の方法より少し速いかもしれませんが、それはまだかなり遅いです。私はそれをdrawInRect:メソッドと組み合わせて、それがそうしているかどうかを調べます。ありがとう。 – Dimitris

+0

実際にはsetNeedsDisplayInRect:はそのトリックを行いました。 – Dimitris

+0

Objective-Cクラスには、インスタンス変数を持つ「メンバー」や「ivars」はありません。 – NSResponder

1

を追加する必要があります。次に、drawRectには、rectパラメータから必要な事前レンダリングされたビットマップの部分だけを描画します。

+0

私はまだこのようなことは試していません。私はおそらくそれを試してみましょう。それがどのように行われたかを示すコードがあれば、それを感謝します。 – Dimitris

+0

++それは私の選択の方法です。私は全体を「blt」するだけです。それは点滅を排除し、瞬時に描画の錯覚を与えます。 –

0

図面をイメージとしてキャッシュすることができれば、UIViewのCoreAnimationバッキングを利用できます。これは、Quartzを使用するよりもはるかに高速です。Quartzはソフトウェアでその描画を行います。

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