32

4冊のiPhone/Cocoa / Core Animation / Objective-Cの本と、Webからの多数のサンプルコードが目の前にあります。それでも、どういうわけか、Quartz2Dで描画がどのように機能するかについての基本的な理解が不足しているように感じます。

drawRect()単に描画コードを実行するためのフックになることを意味しますか?または、この方法は、「損傷」していて再描画が必要な領域も再描画することになっていますか?自分の作品を一度描いてから「くっつく」ことはできますか、それともいつでもシーン全体を塗り直す必要がありdrawRect()ますか?JavaのGraphics2Dオブジェクトはこのように機能します。paint()が呼び出されるたびに「イメージ」全体を描画する必要があるため、いつでも再構築(またはキャッシュ)する準備をする必要があります。

簡単な描画プログラムをどのように実装しますか?drawRect()ユーザーが描いた各線/点/ストロークを「覚えて」、呼び出されるたびにそれを複製する必要がありますか?「オフスクリーン」レンダリングはどうですか。すべての描画を行ってから、呼び出し[self setNeedsDisplay]て書き込みを画面にフラッシュすることはできますか?

ユーザーのタッチに応じて、ユーザーがタッチした画面に「X」を付けたいとしましょう。Xはそこにとどまるはずであり、新しいタッチごとに別のXが生成されます。これらのタッチアップ座標をすべて覚えてから、それらをすべて描画する必要がありdrawRect()ますか?

編集:

私が誤解しない限り、以下のjoconorとHectorRamosの答えは互いに矛盾しています。そして、それはこの主題に関する私の混乱の良いデモンストレーションです。:-)

4

4 に答える 4

38

さまざまな Cocoa リファレンス間の混乱の一部は、Leopard でレイヤーに基づくビューが導入されたことに起因しています。iPhone では、すべての UIView がレイヤーに裏打ちされていますが、Leopard ビューでは、レイヤーに裏打ちされたものを手動で有効にする必要があります。

レイヤーに基づくビューの場合、コンテンツは で指定した内容を使用して 1 回描画されますdrawRect()が、その後レイヤーにバッファーされます。レイヤーは長方形のテクスチャのように機能するため、レイヤーに基づくビューを移動したりカバーしたりする場合、再描画は必要なく、テクスチャは GPU を介してその場所に移動するだけです。needsDisplayOnBoundsChange propertyレイヤーのをに設定しない限りYES、レイヤー (またはレイヤーを含むビュー) のサイズを変更すると、コンテンツが単純にスケーリングされます。これにより、ビューまたはレイヤー内のグラフィックがぼやける可能性があるため、この場合は強制的に再描画することをお勧めします。setNeedsDisplayビューまたはレイヤーのコンテンツの手動再描画と、その後のレイヤー内のそのコンテンツの再キャッシュをトリガーします。

最適なパフォーマンスを得るには、 を頻繁に呼び出さないようにすることをお勧めしますdrawRect。これは、レイヤーでの Quartz の描画と再キャッシュはコストのかかる操作であるためです。移動またはスケーリングできる個別のレイヤーを使用してアニメーションを実行することをお勧めします。

これまで見てきたデスクトップに関連する Cocoa ベースの参照は、層に支えられていないビューを想定している可能性があり、これは drawRect: を呼び出します。ビューを更新する必要があるときはいつでも、それが移動、スケーリング、またはビューの一部を持っているかどうかに関係なく、ビューを更新する必要があります。あいまい。私が言ったように、すべての UIView はレイヤーに裏打ちされているので、これは iPhone には当てはまりません。

つまり、描画アプリケーションの場合、描画オブジェクトの配列を維持して drawRect を呼び出す方法の 1 つです。ユーザーが何か新しいものを追加するたびに、以前に描画された各オブジェクトを順番に反復処理します。描画操作ごとに新しい UIView または CALayer を作成する別のアプローチをお勧めします。その描画操作の内容 (線、円弧、X など) は、個々のビューまたはレイヤーによって描画されます。そうすれば、新しいタッチですべてを再描画する必要がなくなり、描画された各要素を他の要素とは別に移動することで、きちんとしたベクター スタイルの編集を行うことができる場合があります。複雑な描画の場合、これにはメモリのトレードオフが少しあるかもしれませんが、描画パフォーマンスがはるかに優れていると思います (最小限の CPU 使用率とちらつき)。

于 2009-04-04T15:11:05.977 に答える
4

drawRect()はオフスクリーンバッファに描画します。iPhone OSがビューの階層化を処理するため、リージョン自体が「損傷」したときに再描画する必要はありません。バッファに1回書き込むだけで、残りはOSに処理させます。これは、何かがビューを通過するたびに再描画を続ける必要がある他のプログラミング環境とは異なります。

于 2009-04-04T04:26:59.193 に答える
2

drawRect()は、単に描画コードを実行するためのフックを意味しますか?

これは、現在のグラフィックスコンテキストスタックを使用して、渡された領域(rect)を再描画することを目的としています。もういや。

または、この方法は、「損傷」していて再描画が必要な領域も再描画することになっていますか?

いいえ。ダーティリージョンがオーバーラップしていない場合、drawRect:異なるrectが渡されたの複数の呼び出しを受け取る可能性があります。を使用すると、rectは無効になりsetNeedsDisplayInRect:ます。ビューのサーフェスの一部のみを再描画する必要がある場合は、描画するときにその部分を描画するように求められます。

自分のものを一度描画してから「スティック」することはできますか、それともdrawRect()を使用していつでもシーン全体を再描画する必要がありますか?

「くっつかない」。アプリの実行中にrectが無効になり、View Systemが画面を更新する必要があるときに、これらのrectを再描画するように要求されます。要求されたrectのみを再描画します。

場合によっては、単純な実装では、一部が無効になるたびに、ビューのrect全体が(かなり怠惰に)無効になることがあります。これは通常、必要以上の描画が必要であり、ビューが不透明でない場合は特に無駄になるため、通常は問題です。

JavaのGraphics2Dオブジェクトはこのように機能します。paint()が呼び出されるたびに「イメージ」全体を描画する必要があるため、いつでも再構築(またはキャッシュ)する準備をする必要があります。

AppKitやUIKitではそうではありません。

簡単な描画プログラムをどのように実装しますか?ユーザーが描いた各線/点/ストロークを「記憶」し、drawRect()が呼び出されるたびにそれを複製する必要がありますか?

ビューを描画するために必要なコンテキスト(たとえば、各線/点/ストローク)を覚えておく必要があります。要求された領域を描画するだけで済みます。技術的には、グラフィックシステムは、その長方形の外側に描画しても文句を言わないでしょうが、それはアーティファクトにつながる可能性があります。

複雑なレンダリングの場合、外部バッファ(ビットマップなど)に描画してから、事前にレンダリングされたビットマップ表現を使用して、画面に表示する方が簡単または効率的drawrect:です。(レイヤーに関するブラッドの回答も参照してください)

「オフスクリーン」レンダリングはどうですか。すべての描画を行ってから、[self setNeedsDisplay]を呼び出して、書き込みを画面にフラッシュすることができますか?

はい、できます。具体的には、外部バッファー(ビットマップなど)にレンダリングします。ビットマップへのレンダリングが終了したら、描画する四角形を無効にしてから、drawRect:が呼び出されたときにビットマップのデータを使用して画面に描画します。

ユーザーのタッチに応じて、ユーザーがタッチした画面に「X」を付けたいとしましょう。Xはそこにとどまる必要があり、新しいタッチごとに別のXが生成されます。これらのタッチアップ座標をすべて覚えてから、drawRect()ですべて描画する必要がありますか?

さて、あなたにはいくつかの選択肢があります。あなたの提案は1つです(あなたがあなたに渡されたrect内に描くと仮定します)。もう1つは、「X」ビューを作成し、それらのXを起動間も維持する必要がある場合は、ビューを再構築するために必要なポイントを覚えておくだけです。多くの場合、複雑な問題を簡単にレイヤーに分割できます(単純な2Dゲーム)。

  • 1)地平線のある背景画像。
  • 2)頻繁に変更されないフォアグラウンドのいくつかのもの。
  • 3)ユーザーがゲーム内を移動するために使用するキャラクター。

したがって、ほとんどの問題は簡単に分割できるため、常にすべてをレンダリングする必要はありません。これにより、複雑さが軽減され、適切に実行された場合はパフォーマンスが向上します。うまく行かないと、さらに悪化する可能性があります。

于 2011-10-21T20:14:30.073 に答える
2

drawRect:が呼び出されたときは、常にビューの適切な領域を描画する準備をしてください。

システムはビューをバッファリングする場合がありますが、それはdrawRect:呼び出されないようにするだけです。何らかの理由でシステムがバッファを無効にする必要がある場合は、drawRect:メソッドが再度呼び出される可能性があります。また、drawRect:ビューの領域の可視性に影響を与えるスクロールやその他の操作の結果として表示されるようになると、ビューのさまざまな領域に対して呼び出されます。

于 2009-04-04T05:14:01.297 に答える