10

レンダリングに CoreGraphics を使用するペイント アプリに取り組んでいます。私の問題は、パフォーマンスのために、変更されたビューの特定の部分のみに更新を制限しようとしていることです。そのために setNeedsDisplayInRect: を使用しますが、ビューがコンテンツ全体を更新することがあり、途切れが発生します。これは、第 3 世代の iPad で特に顕著ですが、シミュレーターと iPad2 でもより少ない程度で発生します。この動作を削除しようとしています。

この問題を紹介するために、Xcode のテンプレートを使用して単純な「単一ビュー」プロジェクトを作成しました。xib ファイルでビュー コントローラーのビューとして設定したカスタム UIView サブクラスを作成しました。

これを UIViewController に追加しました:

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
    // Asks that the view refreshes a smal rectangle
    [self.view setNeedsDisplayInRect:CGRectMake(10, 10, 20, 20)];
}

これを MyView (私のカスタム ビュー) に追加しました。

- (void)drawRect:(CGRect)rect
{
    // Just log what is being updated
    NSLog(@"%@", NSStringFromCGRect(rect));
}

以上です。3 番目の 10 台の iPad (実際のデバイス) でアプリを実行すると、ログには、ビューが時々 (非常に頻繁に) エンティエで再描画されていることが示されます。これはとてもイライラし、私はアイデアがありません

更新: ここにいくつかのログがあります。完全なビューが時々更新されていることは間違いありません。完全に停止させたいのですが、方法がわかりません...

2012-05-04 08:34:01.851 TestUpdateArea[45745:707] {{0, 0}, {320, 460}}
2012-05-04 08:34:30.184 TestUpdateArea[45745:707] {{0, 0}, {320, 460}}
2012-05-04 08:34:30.197 TestUpdateArea[45745:707] {{0, 0}, {320, 460}}
2012-05-04 08:34:30.215 TestUpdateArea[45745:707] {{10, 10}, {20, 20}}
2012-05-04 08:34:30.226 TestUpdateArea[45745:707] {{10, 10}, {20, 20}}
2012-05-04 08:34:30.242 TestUpdateArea[45745:707] {{10, 10}, {20, 20}}
2012-05-04 08:34:30.258 TestUpdateArea[45745:707] {{10, 10}, {20, 20}}
2012-05-04 08:34:30.274 TestUpdateArea[45745:707] {{10, 10}, {20, 20}}
2012-05-04 08:34:30.290 TestUpdateArea[45745:707] {{10, 10}, {20, 20}}
2012-05-04 08:34:30.306 TestUpdateArea[45745:707] {{10, 10}, {20, 20}}
2012-05-04 08:34:30.322 TestUpdateArea[45745:707] {{10, 10}, {20, 20}}
2012-05-04 08:34:30.338 TestUpdateArea[45745:707] {{10, 10}, {20, 20}}
2012-05-04 08:34:30.354 TestUpdateArea[45745:707] {{10, 10}, {20, 20}}
2012-05-04 08:34:30.371 TestUpdateArea[45745:707] {{10, 10}, {20, 20}}
2012-05-04 08:34:30.387 TestUpdateArea[45745:707] {{10, 10}, {20, 20}}
2012-05-04 08:34:30.403 TestUpdateArea[45745:707] {{10, 10}, {20, 20}}
2012-05-04 08:34:30.419 TestUpdateArea[45745:707] {{10, 10}, {20, 20}}
2012-05-04 08:34:30.439 TestUpdateArea[45745:707] {{0, 0}, {320, 460}}
2012-05-04 08:34:30.457 TestUpdateArea[45745:707] {{10, 10}, {20, 20}}

また、10 秒以上移動を停止して再開すると、確実に非常に一貫して動作します。

2012-05-04 08:34:33.305 TestUpdateArea[45745:707] {{10, 10}, {20, 20}}
2012-05-04 08:34:33.321 TestUpdateArea[45745:707] {{10, 10}, {20, 20}}
2012-05-04 08:35:00.202 TestUpdateArea[45745:707] {{0, 0}, {320, 460}}
2012-05-04 08:35:00.221 TestUpdateArea[45745:707] {{0, 0}, {320, 460}}
2012-05-04 08:35:00.234 TestUpdateArea[45745:707] {{0, 0}, {320, 460}}
2012-05-04 08:35:00.251 TestUpdateArea[45745:707] {{10, 10}, {20, 20}}
4

4 に答える 4

13

受け入れられた答えは間違っています(または少なくとも誤解を招きます)。

setNeedsDisplayInRect: の簡単なコード例を次に示します。

http://charcoaldesign.co.uk/resources/chalkboard.zip

Apple のドキュメントは、iOS ではすべてのビュー バッキング イメージが OpenGL テクスチャに変換され、画面全体がフレームごとに再合成されるという事実を説明しようとしていると思われます。これは、ビューのバッキング テクスチャの内容全体をコードでクリアして再描画する必要があるかどうかという問題とは異なります。

setNeedsDisplayInRect: を使用することで、フレーム間で変化しない (コア グラフィックスを使用し、ハードウェア アクセラレーションを使用しない) コンテンツのコストのかかる再描画を回避できます。それでも画面全体が再描画されますが、drawRect のコードとは異なり、GPU によって高速化されたハードウェアであるため問題ありません。

于 2013-05-31T08:47:18.467 に答える
5

このアップルのドキュメントを確認してください

彼らは言った :

iPhone/iPod touch/iPad が画面を更新する方法のため、-setNeedsDisplayInRect:または を呼び出すとビュー全体が再描画されます-setNeedsDisplay:

また

各 UIView は単一の要素として扱われます。-setNeedsDisplayInRect:またはを呼び出して、部分的または全体的に再描画を要求すると、-setNeedsDisplay:ビュー全体が更新対象としてマークされます。

ビュー全体の独立した四角形を更新するには、サブビューを使用する必要があると思います。

于 2012-05-10T07:36:25.213 に答える
0

同様の問題があります。つまり、UIView の一部のみを setNeedsDisplayInRect: の呼び出しで更新したいのですが、正しいサイズの有効な CGRect を渡します (ブレークポイントとログで証明されています)。iOS 4.2.1 (iPhone 3G) では UIView は元の画像を保持し、CGRect で指定された部分のみを更新しますが、iOS 5.1 (iPhone 4S) では UIView 全体が透明な黒で再描画されます (どのように黒くなるか)透明は私を超えています)、CGRect によって指定された領域が後で正しく描画されます。次のいずれかのようです: setNeedsDisplayInRect: を正しく実装しておらず、単に setNeedsDisplay:; に渡しているという Apple 側のエラーです。または、新しい iOS が実際の画面アーキテクチャとのやり取りをどのように処理するかに基づいて、故意に決定したものです。どちらにしても、

UIView プロパティ clearsContextBeforeDrawing (ドキュメントによると、対象となる描画操作を許可する必要があります) を使用していくつかのテストを行いましたが、結果は YES と NO の両方で同じであるため、描画コードの実装のように見えます。

更新中の CGRect のサイズが正しくないことについては、描画呼び出しの前または後に別の場所に設定されていますか。setNeedsDisplayInRect: の呼び出しの直前に CGRect を設定し、drawRect メソッドの最後の数行で CGRectNull に設定します (これは、drawRect メソッドがシステムによって呼び出された場合、コードが実行されないためです)。コード スニペットに戻ると、インラインで設定されていることがわかります。つまり、UIView 全体を再描画するシステム コールであるため、CGRect がビュー全体である理由が分かります。

私はこれを掘り下げ続けますが、Apple が setNeedsDisplayInRect: への変更の理由を明らかにするか、明らかなバグを修正するまで、グラフィカルな更新ごとに UIView の内容全体を更新することを検討しているのではないかと心配しています (これは可能性があります)。非常に「高価」になる可能性があります)。

于 2012-05-11T16:32:12.057 に答える