web-dev-qa-db-ja.com

`Region.Op.REPLACE`で` canvas.clipRect`に代わる最良の選択肢は何ですか?

バックグラウンド

私は複数のビューの代わりに多くのキャンバス描画を持つライブラリに取り組んでいます(利用可能 here )。

問題

アプリを改善し、アプリのニーズに合わせて機能させるため(カスタマイズが必要)、非推奨としてマークされている行があることに気付きました。

canvas.clipRect(0f, mHeaderHeight + mHeaderRowPadding * 2, mHeaderColumnWidth, height.toFloat(), Region.Op.REPLACE)

ことは、このコード行を新しいAPIに置き換える良い候補があるとは思わない

私が見つけたもの

thedocs を見ると、これが書かれているものです:

このメソッドは、APIレベル26で廃止されました。INTERSECTおよびDIFFERENCE以外のRegion.Op値には、クリップを展開する機能があります。キャンバスクリッピングAPIは、復元操作の結果としてのみクリップを展開することを目的としています。これにより、ビューの親はキャンバスをクリップして、子の最大描画領域を明確に定義できます。推奨される代替呼び出しは、clipRect(RectF)およびclipOutRect(RectF)です。

そのため、これらの関数のいずれかを使用しようとしましたが、どちらも以前の方法の描画に問題を引き起こしました。

非推奨を見ると、関数自体はマークされているようですが、Region.Op.REPLACEはマークされていないようです:

enter image description here

だから多分それは本当に代替手段を持っていない...

質問

  1. この場合の最良の選択肢は何ですか?
  2. なぜ非推奨になったのですか?
  3. いくつかの廃止された関数とは対照的に、私はこれが代替手段を見つけることができない場合に使用するのに安全であるべきだと思いますか?
12

1:カスタムRegion.Opを使用するすべてのメソッドは非推奨になったため、現在は2つのメソッドバリアントclipRect/clipPathRegion.Op.INTERSECTを表す)とclipOutRect/clipOutPathRegion.Op.DIFFERENCEを表します)。 Region.Op.REPLACEに似た機能を実現するには、save()およびrestore()メソッドを使用する必要があります。

したがって、以前は(Op.REPLACEを使用して)次のように呼び出すだけでした。

canvas.clipRect(0, 0, 100, 100); // do some clipping
canvas.drawLine(...); // do some clipped drawing

canvas.clipRect(200, 200, 400, 400, Region.Op.REPLACE); // replace clipping region to completely different one
canvas.drawLine(...); // and some other drawing

ただし、手動で以前のキャンバス状態を保存および復元する必要があります。

canvas.save();        // IMPORTANT: save current state of clip and matrix (i.e. unclipped state) (let's say it's state #1)
canvas.clipRect(0, 0, 100, 100); // do some clipping
canvas.drawLine(...); // do some clipped drawing
canvas.restore();     // IMPORTANT: get back to previously saved (unclipped) state of the canvas (restores state #1)

canvas.save(); // now save again the current state of canvas (clip and matrix) (it's state #2)
canvas.clipRect(200, 200, 400, 400); // now we can do some other clipping (as we would do with Region.Op.REPLACE before)
canvas.drawLine(...); // and some other drawing
canvas.restore(); // get back go previously saved state (to state #2)

メモCanvasは内部的にスタックを使用しているため、異なる瞬間にsave()を複数回呼び出すこともできます。 canvas.restore()が呼び出された回数以上canvas.save()を呼び出すことはできません。

また、canvas.restore()を呼び出すと、クリップrectが変更されます(canvas.save()があったときと同じ値になります)と呼ばれます)。したがって、クリッピングを適用する必要があるすべての描画メソッドの後に、restore()呼び出しを慎重に配置する必要があります。

2:おそらくパフォーマンスの最適化が原因です。 GPUのハードウェアアクセラレーションでは、INTERSECT/DIFFERENCEクリップ操作のみを使用でき、他の操作はCPU処理にフォールバックする必要があることをどこかで読んだと思います(今は見つかりませんでした)。それが理由かもしれません。

編集: ここ はいくつかの関連する答えです。ICS HWアクセラレーションを有効にするとClipRectの一部の操作がサポートされないためです。

3:彼らがドキュメントで言うように、それはAndroid P(おそらくAndroid P)をターゲットとする場合のみ:

APIレベル現在、APIレベルBuild.VERSION_CODES.Pは、INTERSECTおよびDIFFERENCEのみが有効なRegion.Opパラメーターです。

26
Robyer