web-dev-qa-db-ja.com

FlutterでCustomMultiChildLayoutとCustomSingleChildLayoutを使用する方法

CustomSingleChildLayout および CustomMultiChildLayout クラスの使用経験がある人は、それらの使用方法を(例を挙げて)詳細に説明できますか?.

私はFlutterを初めて使用し、これらの使用方法を理解しようとしています。ただし、ドキュメントは恐ろしく、明確ではありません。例としてインターネットを調べようとしましたが、他のドキュメントはありません。

あなたが助けてくれるなら、私は永遠に感謝します。

ありがとうございました!

10
Walter M

まず第一に、私はあなたの苦労を理解できるので、これであなたを助けてうれしいと言いたいです-自分でそれを理解することにも利点があります(ドキュメントは素晴らしいです)。

CustomSingleChildLayoutの説明は、CustomMultiChildLayoutを説明した後で明らかになります。

CustomMultiChildLayout

このウィジェットのポイントは、このウィジェットに渡す子を1つの関数でlayoutできるようにすることです。つまり、位置とサイズは相互に依存する可能性があります、これはあなたがを使って達成できないものです。例:ビルド済みのStackウィジェット。

_CustomMultiChildLayout(
  children: [
    // Widgets you want to layout in a customized manner
  ],
)
_

今、あなたはあなたの子供を配置し始めることができる前に取る必要があるあと2つのステップがあります:

  1. childrenに渡すすべての子は LayoutId である必要があり、実際に子として表示したいウィジェットをそのLayoutIdに渡します。 idはウィジェットを一意に識別し、レイアウト時にウィジェットにアクセスできるようにします。
_CustomMultiChildLayout(
  children: [
    LayoutId(
      id: 1, // The id can be anything, i.e. any Object, also an enum value.
      child: Text('Widget one'), // This is the widget you actually want to show.
    ),
    LayoutId(
      id: 2, // You will need to refer to that id when laying out your children.
      child: Text('Widget two'),
    ),
  ],
)
_
  1. レイアウトパーツを処理する MultiChildLayoutDelegate サブクラスを作成する必要があります。ここのドキュメントは非常に複雑なようです。
_class YourLayoutDelegate extends MultiChildLayoutDelegate {
  // You can pass any parameters to this class because you will instantiate your delegate
  // in the build function where you place your CustomMultiChildLayout.
  // I will use an Offset for this simple example.

  YourLayoutDelegate({this.position});

  final Offset position;
}
_

これですべての設定が完了し、実際のレイアウトの実装を開始できます。そのために使用できる方法は3つあります。

  • hasChild 、特定のidかどうかを確認できます(LayoutId?を覚えておいてください) childrenに渡されました。つまり、そのIDの子が存在する場合。

  • layoutChild 、すべてのid、すべての子、提供された正確に1回、その子のSizeが得られます。

  • positionChild 。これにより、位置をOffset(0, 0)から指定したオフセットに変更できます。

概念は今やかなり明確になっているはずです。そのため、CustomMultiChildLayoutの例のデリゲートを実装する方法を説明します。

_class YourLayoutDelegate extends MultiChildLayoutDelegate {
  YourLayoutDelegate({this.position});

  final Offset position;

  @override
  void performLayout(Size size) {
    // `size` is the size of the `CustomMultiChildLayout` itself.

    Size leadingSize = Size.zero; // If there is no widget with id `1`, the size will remain at zero.
    // Remember that `1` here can be any **id** - you specify them using LayoutId.
    if (hasChild(1)) {
      leadingSize = layoutChild(
        1, // The id once again.
        BoxConstraints.loose(size), // This just says that the child cannot be bigger than the whole layout.
      );
      // No need to position this child if we want to have it at Offset(0, 0).
    }

    if (hasChild(2)) {
      final secondSize = layoutChild(
        2,
        BoxConstraints(
          // This is exactly the same as above, but this can be anything you specify.
          // BoxConstraints.loose is a shortcut to this.
          maxWidth: size.width,
          maxHeight: size.height,
        ),
      );

      positionChild(
        2,
        Offset(
          leadingSize.width, // This will place child 2 to the right of child 1.
          size.height / 2 - secondSize.height / 2, // Centers the second child vertically.
        ),
      );
    }
  }
}
_

他の2つの例は、ドキュメントからの例です(準備を確認step 2)と実世界_feature_discovery_ パッケージ: MultiChildLayoutDelegate implementation および CustomMultiChildLayout in buildメソッド

最後のステップは shouldRelayout method をオーバーライドすることです。これは、古いデリゲートと比較して、任意の時点でperformLayoutを再度呼び出すかどうかを簡単に制御します(オプションで getSize )をオーバーライドして、デリゲートをCustomMultiChildLayoutに追加することもできます。

_class YourLayoutDelegate extends MultiChildLayoutDelegate {
  YourLayoutDelegate({this.position});

  final Offset position;

  @override
  void performLayout(Size size) {
    // ... (layout code from above)
  }

  @override
  bool shouldRelayout(YourLayoutDelegate oldDelegate) {
    return oldDelegate.position != position;
  }
}
_
_CustomMultiChildLayout(
  delegate: YourLayoutDelegate(position: Offset.zero),
  children: [
    // ... (your children wrapped in LayoutId's)
  ],
)
_

考慮事項

  • この例では、idsとして_1_および_2_を使用しましたが、enumを使用することはおそらく特定のIDがある場合にIDを処理する最良の方法。

  • Listenablesuperに渡すことができます(例:super(relayout: animation))。これは、レイアウトプロセスをアニメーション化したり、一般にリスナブルに基づいてトリガーしたりする場合に使用します。

CustomSingleChildLayout

ドキュメント は、私が上で説明したことを非常によく説明し、ここで、CustomSingleChildLayoutCustomMultiChildLayoutの仕組みを理解した後で非常に明白になると言った理由もわかります。

CustomMultiChildLayout は、複数のウィジェットのサイズと配置の間に複雑な関係がある場合に適しています。単一の子のレイアウトを制御するには、 CustomSingleChildLayout がより適切です。

これはまた、CustomSingleChildLayoutを使用すると、上記で説明したのと同じ原則に従いますが、子が1つしかないため、IDはありません。
代わりに SingleChildLayoutDelegate を使用する必要があります。これには、レイアウトを実装するためのさまざまなメソッドがあります(これらにはすべてデフォルトの動作があるため、技術的にすべてオーバーライド):

それ以外はまったく同じです(LayoutIdは必要なく、childrenではなく子が1つしかないことに注意してください)。


MultiChildRenderObjectWidget

これがCustomMultiChildLayoutの土台です。
これを使用するには、Flutterに関するさらに深い知識が必要であり、やはり少し複雑ですが、レベルがさらに低いため、より多くのカスタマイズが必要な場合は、このオプションが適しています。これには、CustomMultiChildLayoutよりもmajorの利点が1つあります(通常、より多くの制御があります)。

CustomMultiChildLayoutサイズを指定できません自身に基づいてその子推論のためのより良いドキュメントに関する問題 を参照)。

ここではMultiChildRenderObjectWidgetの使用方法を明確な理由で説明しませんが、興味がある場合は、チェックアウトできます フラッタークロックチャレンジへの私の提出 2020年1月20日以降私はMultiChildRenderObjectWidgetを広範に使用しています。 これに関する記事 を読むこともできます。これにより、すべてがどのように機能するかが少し説明されます。

今のところ、MultiChildRenderObjectWidgetCustomMultiChildLayoutを可能にするものであり、それを直接使用すると、LayoutIdを使用する必要がなく、代わりにRenderObjectの親データを直接。

楽しい事実

私はすべてのコードをプレーンテキスト(StackOverflowテキストフィールド)で記述したので、エラーが発生した場合は指摘してください。修正します。