<

クリップの動作

まとめ

Flutter のデフォルトは次のとおりですいいえいくつかの特殊なウィジェットを除いてクリップします (そのようなClipRect)。クリップなしのデフォルトをオーバーライドするには、 明示的に設定clipBehaviorウィジェットの構造で。

コンテクスト

以前はクリップのせいで flutterが遅かったです。例えば、 Flutter ギャラリー アプリのベンチマークは平均フレームでした 2018年5月のラスタライズ時間は約35ミリ秒、 ここで、スムーズな 60fps レンダリングの予算は 16 ミリ秒です。 不要なクリップとそれに関連する操作を削除することで、 35 ミリ秒/フレームから 17.5 ミリ秒/フレームへ、ほぼ 2 倍の速度向上が見られました。

当時のクリッピングに関連する最大のコストは、Flutter を追加するために使用されますsaveLayer各クリップの後に呼び出します (単純な場合を除く) 軸に合わせた長方形クリップ) を使用して、ブリーディング エッジ アーティファクトを回避します。 で説明されているように問題 18057。そのような行動は普遍的でした のようなウィジェットを介したマテリアルアプリCardChipButton、 等々、 その結果、PhysicalShapePhysicalModelコンテンツをクリッピングします。

saveLayer古いデバイスでは特に通話料金が高くなります。 オフスクリーン レンダー ターゲットとレンダー ターゲット スイッチを作成します。 場合によっては約 1 ミリ秒かかることがあります。

なくてもsaveLayer電話してください、クリップはまだ高価です 復元されるまで、それ以降のすべての描画に適用されるためです。 したがって、単一のクリップによってパフォーマンスが低下する可能性があります。 何百もの描画操作。

パフォーマンスの問題に加えて、Flutter は次のような問題も抱えていました。 クリップが管理および実装されていないため、正確性の問題がいくつか発生しました 一か所で。いくつかの場所で、saveLayer挿入されました 間違った場所にあったため、パフォーマンスが向上しただけです 最先端のアーティファクトを修正することなく、コストを削減します。

そこで、統一したのが、clipBehavior制御とその実装 この画期的な変更。デフォルトclipBehaviorClip.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 つの選択肢があります。

  1. コンテンツが必要ない場合は、コードをそのままにしておきます クリップされる (たとえば、ウィジェットの子はどれもクリップされない) 親の境界の外に拡張します)。 これはアプリの動作にプラスの影響を与える可能性があります。 全体的なパフォーマンス。
  2. 追加clipBehavior: Clip.hardEdgeクリッピングが必要な場合は、 アンチエイリアスなしのクリッピングは、 (そしてあなたのクライアントの)目。これはよくあるケースです 非常に小さな湾曲領域を持つ長方形または形状をクリップする場合 (角丸長方形の角など)。
  3. 追加clipBehavior: Clip.antiAlias必要であれば アンチエイリアス付きクリッピング。これにより、より滑らかなエッジが得られます わずかに高いコストで。これはよくあるケースです 円と円弧を扱います。
  4. 追加clip.antiAliasWithSaveLayer正確な情報が必要な場合は 以前 (2018 年 5 月) と同じ動作。であることに注意してください パフォーマンスに非常にコストがかかります。おそらくこれだけです ほとんど必要ありません。これが必要になる可能性があるのは、次のような場合です。 非常に異なる背景色に画像が重ねられています。 このような場合は、重複を避けることができるかどうかを検討してください。 1 つのスポットに複数の色を配置する (たとえば、 背景色は画像が存在しない場所にのみ存在します)。

のためにStack特にウィジェットを以前に使用した場合overflow: Overflow.visibleに置き換えてくださいclipBehavior: Clip.none

のためにListWheelViewportウィジェット (以前に指定した場合)clipToSize、対応するものに置き換えてくださいclipBehavior:Clip.noneためにclipToSize = falseClip.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 クリップがありません