クリップの動作
まとめ
Flutter のデフォルトは次のとおりですいいえいくつかの特殊なウィジェットを除いてクリップします
(そのようなClipRect
)。クリップなしのデフォルトをオーバーライドするには、
明示的に設定clipBehavior
ウィジェットの構造で。
コンテクスト
以前はクリップのせいで flutterが遅かったです。例えば、 Flutter ギャラリー アプリのベンチマークは平均フレームでした 2018年5月のラスタライズ時間は約35ミリ秒、 ここで、スムーズな 60fps レンダリングの予算は 16 ミリ秒です。 不要なクリップとそれに関連する操作を削除することで、 35 ミリ秒/フレームから 17.5 ミリ秒/フレームへ、ほぼ 2 倍の速度向上が見られました。
当時のクリッピングに関連する最大のコストは、Flutter
を追加するために使用されますsaveLayer
各クリップの後に呼び出します (単純な場合を除く)
軸に合わせた長方形クリップ) を使用して、ブリーディング エッジ アーティファクトを回避します。
で説明されているように問題 18057。そのような行動は普遍的でした
のようなウィジェットを介したマテリアルアプリCard
、Chip
、Button
、 等々、
その結果、PhysicalShape
とPhysicalModel
コンテンツをクリッピングします。
あsaveLayer
古いデバイスでは特に通話料金が高くなります。
オフスクリーン レンダー ターゲットとレンダー ターゲット スイッチを作成します。
場合によっては約 1 ミリ秒かかることがあります。
なくてもsaveLayer
電話してください、クリップはまだ高価です
復元されるまで、それ以降のすべての描画に適用されるためです。
したがって、単一のクリップによってパフォーマンスが低下する可能性があります。
何百もの描画操作。
パフォーマンスの問題に加えて、Flutter は次のような問題も抱えていました。
クリップが管理および実装されていないため、正確性の問題がいくつか発生しました
一か所で。いくつかの場所で、saveLayer
挿入されました
間違った場所にあったため、パフォーマンスが向上しただけです
最先端のアーティファクトを修正することなく、コストを削減します。
そこで、統一したのが、clipBehavior
制御とその実装
この画期的な変更。デフォルトclipBehavior
はClip.none
以下を除くほとんどのウィジェットでパフォーマンスを節約します。
-
ClipPath
デフォルトはClip.antiAlias
-
ClipRRect
デフォルトはClip.antiAlias
-
ClipRect
デフォルトはClip.hardEdge
-
Stack
デフォルトはClip.hardEdge
-
EditableText
デフォルトはClip.hardEdge
-
ListWheelScrollView
デフォルトはClip.hardEdge
-
SingleChildScrollView
デフォルトはClip.hardEdge
-
NestedScrollView
デフォルトはClip.hardEdge
-
ShrinkWrappingViewport
デフォルトはClip.hardEdge
移行ガイド
コードを移行するには 4 つの選択肢があります。
- コンテンツが必要ない場合は、コードをそのままにしておきます クリップされる (たとえば、ウィジェットの子はどれもクリップされない) 親の境界の外に拡張します)。 これはアプリの動作にプラスの影響を与える可能性があります。 全体的なパフォーマンス。
- 追加
clipBehavior: Clip.hardEdge
クリッピングが必要な場合は、 アンチエイリアスなしのクリッピングは、 (そしてあなたのクライアントの)目。これはよくあるケースです 非常に小さな湾曲領域を持つ長方形または形状をクリップする場合 (角丸長方形の角など)。 - 追加
clipBehavior: Clip.antiAlias
必要であれば アンチエイリアス付きクリッピング。これにより、より滑らかなエッジが得られます わずかに高いコストで。これはよくあるケースです 円と円弧を扱います。 - 追加
clip.antiAliasWithSaveLayer
正確な情報が必要な場合は 以前 (2018 年 5 月) と同じ動作。であることに注意してください パフォーマンスに非常にコストがかかります。おそらくこれだけです ほとんど必要ありません。これが必要になる可能性があるのは、次のような場合です。 非常に異なる背景色に画像が重ねられています。 このような場合は、重複を避けることができるかどうかを検討してください。 1 つのスポットに複数の色を配置する (たとえば、 背景色は画像が存在しない場所にのみ存在します)。
のためにStack
特にウィジェットを以前に使用した場合overflow: Overflow.visible
に置き換えてくださいclipBehavior: Clip.none
。
のためにListWheelViewport
ウィジェット (以前に指定した場合)clipToSize
、対応するものに置き換えてくださいclipBehavior
:Clip.none
ためにclipToSize = false
とClip.hardEdge
ためにclipToSize = true
。
移行前のコード:
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: Center(
child: Stack(
overflow: Overflow.visible,
children: const <Widget>[
SizedBox(
width: 100,
height: 100,
),
],
),
),
),
);
移行後のコード:
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: Center(
child: Stack(
clipBehavior: Clip.none,
children: const <Widget>[
SizedBox(
width: 100.0,
height: 100.0,
),
],
),
),
),
);
タイムライン
リリースされたバージョン:様々
安定版リリース: 2.0.0
参考文献
API ドキュメント:
Clip
関連する問題:
- 問題 13736
- 問題 18057
- 問題 21830
関連する PR:
- PR 5420: 不要なsaveLayerを削除します
- PR 18576: クリップ列挙型をマテリアルおよび関連ウィジェットに追加します
- PR 18616: ダーツからクリップした後にsaveLayerを削除します
- PR 5647: ClipMode を ClipPath/ClipRRect および PhysicalShape レイヤーに追加します
- PR 5670: キャンバス クリップ呼び出しにアンチエイリアス スイッチを追加します
- PR 5853: クリップモードの名前をクリップ動作に変更します
- PR 5868: compositing.dart でクリップの名前を ClipBehavior に変更します
- PR 5973: クリップがある場合は、drawPath の代わりにdrawPaint を呼び出します。
- PR 5952: 可能であればクリップなしでdrawPathを呼び出します。
- PR 20205: デフォルトの ClipBehavior を Clip.none に設定し、テストを更新します
- PR 20538: ClipBehavior をより多くのマテリアル ボタンに公開します
- PR 20751: CustomBorder を InkWell に追加して、ShapeBorder をクリップできるようにします
- PR 20752: デフォルトのクリップを再度 Clip.none に設定します
- PR 21012: デフォルトのノークリップテストをより多くのボタンに追加します
- PR 21703: ClipRectのデフォルトのclipBehaviorをhardEdgeに設定
- PR 21826: ClipRectLayer のデフォルトの HardEdge クリップがありません