Chapter 05

 03. 複数子を持つWidget

cxj
cxj
2024.07.12に更新

本節では複数子を持つレイアウトウェジェットFlex、Row、Column、Wrap、Stackを解説します。

Flex/Row/Column

RowとColumnはFlexを継承していて、directionはAxis.horizontalとAxis.verticalのウェジェットである、すなわち、RowとColumnはFlexのdirection属性を固定したもの。

コンストラクター

  Flex({
    Key? key,
    required this.direction,
    this.mainAxisAlignment = MainAxisAlignment.start,
    this.mainAxisSize = MainAxisSize.max,
    this.crossAxisAlignment = CrossAxisAlignment.center,
    this.textDirection,
    this.verticalDirection = VerticalDirection.down,
    this.textBaseline, // NO DEFAULT: we don't know what the text's baseline should be
    this.clipBehavior = Clip.none,
    List<Widget> children = const <Widget>[],
  }) : assert(direction != null),
       assert(mainAxisAlignment != null),
       assert(mainAxisSize != null),
       assert(crossAxisAlignment != null),
       assert(verticalDirection != null),
       assert(crossAxisAlignment != CrossAxisAlignment.baseline || textBaseline != null, 'textBaseline is required if you specify the crossAxisAlignment with CrossAxisAlignment.baseline'),
       assert(clipBehavior != null),
       super(key: key, children: children);

属性

属性 説明
direction 主軸の方向
mainAxisAlignment メイン軸/主軸に対する整列
mainAxisSize 主軸のサイズ
crossAxisAlignment クロス軸/交差軸の整列
textDirection 文字列の方向
verticalDirection 垂直方向
textBaseline 文字列のベースライン

direction

  • Axis.horizontal
    子ウェジェットたちの並び方向を水平にする。Axis.horizontalに定義した時はRowと同じものと見られる。
  • Axis.vertical
    子ウェジェットたちの並び方向を垂直にする。Axis.verticalに定義した時はColumnと同じものと見られる。

mainAxisAlignment

メイン軸/主軸に対する整列、Rowの場合は横方向の整列、Columは縦方向整列

/// How the children should be placed along the main axis in a flex layout.
///
/// See also:
///
///  * [Column], [Row], and [Flex], the flex widgets.
///  * [RenderFlex], the flex render object.
enum MainAxisAlignment {
  • MainAxisAlignment.start
    始点から整列
  • MainAxisAlignment.end
    末尾から整列
  • MainAxisAlignment.center
    センターから整列
  • MainAxisAlignment.spaceBetween
    両端を揃える。つまり、最初の子が左側にあり、最後の子が右側にあり、残りの子が中央に均等に分散される。
  • MainAxisAlignment.spaceAround
    各子の左右の間隔を等しくする、つまりmarginは等しい。
  • MainAxisAlignment.spaceEvenly
    各子は均等に分散される。つまり、幅は同じ。

Rowを例として確認します。

MainAxisAlignment

mainAxisSize

主軸のサイズ、デフォルトはMainAxisSize.max
制約条件による機能する、親の制約は緩い場合のみ機能する。
MainAxisSize.maxは制約サイズ最大に伸ばせる
https://github.com/ling350181/flutter_ui/blob/main/lib/mult_child/row_main_axis_size_page.dart
mainAxisSize

verticalDirection

子ウェジェットの整列順序、デフォルトはdown
down:topからbottom
up:bottomからtop

crossAxisAlignment

/// How the children should be placed along the cross axis in a flex layout.
///
/// See also:
///
///  * [Column], [Row], and [Flex], the flex widgets.
///  * [RenderFlex], the flex render object.
enum CrossAxisAlignment {
  /// Place the children with their start edge aligned with the start side of
  /// the cross axis.
  • CrossAxisAlignment.start
    Rowは縦方向の上から整列
  • CrossAxisAlignment.end
    Rowは縦方向の下から整列
  • CrossAxisAlignment.center
    Rowは縦方向の中心より、整列する
  • CrossAxisAlignment.stretch
    子を拡大し、親のレイアウトを埋める
  • CrossAxisAlignment.baseline
    ベースラインを基準に整列する

※クロス軸のcrossAxisAlignment.startとendはverticalDirectionの属性により、影響を与える。verticalDirectionデフォルトはVerticalDirection.downだが、upの時、crossAxisAlignment.startとendの効果は逆になる。
ベースラインを使う際、textBaselineの属性を定義しないといけない

crossAxisAlignment

Wrap

コンストラクター

class Wrap extends MultiChildRenderObjectWidget {
  /// Creates a wrap layout.
  ///
  /// By default, the wrap layout is horizontal and both the children and the
  /// runs are aligned to the start.
  ///
  /// The [textDirection] argument defaults to the ambient [Directionality], if
  /// any. If there is no ambient directionality, and a text direction is going
  /// to be necessary to decide which direction to lay the children in or to
  /// disambiguate `start` or `end` values for the main or cross axis
  /// directions, the [textDirection] must not be null.
  Wrap({
    Key? key,
    this.direction = Axis.horizontal,
    this.alignment = WrapAlignment.start,
    this.spacing = 0.0,
    this.runAlignment = WrapAlignment.start,
    this.runSpacing = 0.0,
    this.crossAxisAlignment = WrapCrossAlignment.start,
    this.textDirection,
    this.verticalDirection = VerticalDirection.down,
    this.clipBehavior = Clip.none,
    List<Widget> children = const <Widget>[],
  }) : assert(clipBehavior != null), super(key: key, children: children);

属性

属性 説明
direction 主軸の方向
alignment 新しく一行できたとき、主軸に対する整列
spacing 主軸の方向の子ウェジェットの間隔
runAlignment runの整列。行ごとのクロス軸の整列方式
runSpacing runの間隔
crossAxisAlignment 行の子ウェジェットのクロス軸の整列方向
textDirection Flexと同じく、文字列の整列方向
verticalDirection 垂直方向の整列順序
clipBehavior 端を超えてエッジをトリミングする方法

direction

WrapのdirectionデフォルトAxis.horizontal(水平方向)
direction

alignment

新しく一行できたとき、主軸に対する整列

  • WrapAlignment.start
    始点から整列
  • WrapAlignment.end
    末尾から整列
  • WrapAlignment.center
    センターから整列
  • WrapAlignment.spaceBetween
    両端を揃える。つまり、最初の子が左側にあり、最後の子が右側にあり、残りの子が中央に均等に分散される。
  • WrapAlignment.spaceAround
    各子の左右の間隔を等しくする、つまりmarginは等しい。
  • WrapAlignment.spaceEvenly
    各子は均等に分散される。つまり、幅は同じ。

alignment

runAlignment

runの整列。行ごとのクロス軸の整列方式。alignmentと同じ列挙型のWrapAlignmentを使われている。

runAlignment

crossAxisAlignment

各行の子ウェジェットのクロス軸整列方式

enum WrapCrossAlignment {
  start,
  end,
  center,
}

crossAxisAlignment

textDirection

水平方向の整列方向

  • TextDirection.ltr
    左から右
  • TextDirection.rtl
    右から左
    textDirection

verticalDirection

垂直方向の整列順序

  • VerticalDirection.down
    上から下
  • VerticalDirection.up
    下から上
    verticalDirection

間隔spacingとrunSpacing

spacingは主軸の各子ウェジェットの間隔を定義する、runSpacingは各行の間隔を定義する。

spacing

Stack

Stackとは

スタックは、上下左右の制約を指定できる絶対レイアウトコンポーネントとして使用されます。複数の子をオーバーラップさせたい場合に役立ちます。

コンストラクター

  const Stack({
    super.key,
    this.alignment = AlignmentDirectional.topStart,
    this.textDirection,
    this.fit = StackFit.loose,
    this.clipBehavior = Clip.hardEdge,
    super.children,
  });

属性

属性 説明
alignment アラインメント形式、制約なしの子に適用する
textDirection レイアウト方向、制約なしの子に適用する
fit 制約設定していない子ウィジェットの充填方式
clipBehavior スタックの端を超えてエッジをトリミングする方法
  • clipBehavior
    • Clip.none(クリップしない)
    • Clip.hardEdge(クリップするが、アンチエイリアシングは適用しない)
    • Clip.antiAlias(アンチエイリアシングでクリップする)
    • Clip.antiAliasWithSaveLayer(クリップの直後にアンチエイリアシングとsaveLayerを使用してクリップする)

RowとColumnと比較して、StackとPositionedコンビネーションで使用することが多いです。上、下、左、右、および幅と高さの制約を設定して、絶対レイアウトすることができます。

alignment

(0.0, 0.0)を中心に、9のアラインメント形式がある

  • AlignmentDirectional topStart = AlignmentDirectional(-1.0, -1.0)
  • AlignmentDirectional topCenter = AlignmentDirectional(0.0, -1.0)
  • AlignmentDirectional topEnd = AlignmentDirectional(1.0, -1.0)
  • AlignmentDirectional centerStart = AlignmentDirectional(-1.0, 0.0)
  • AlignmentDirectional center = AlignmentDirectional(0.0, 0.0)
  • AlignmentDirectional centerEnd = AlignmentDirectional(1.0, 0.0)
  • AlignmentDirectional bottomStart = AlignmentDirectional(-1.0, 1.0)
  • AlignmentDirectional bottomCenter = AlignmentDirectional(0.0, 1.0)
  • AlignmentDirectional bottomEnd = AlignmentDirectional(1.0, 1.0)
    alignment

textDirection

並び方向

  • TextDirection.rtl(右から左)
  • TextDirection.ltr(左から右)
    textDirection

fit

サイズや位置制約してないウィジェットに対する充填方式の定義です。
(Positionedではない子の充填方式)

  • StackFit.loose(ゆるい)
  • StackFit.expand(拡大)
  • StackFit.passthrough(通り過ぎる)
    親からスタックに渡される制約は、位置やサイズ制約されていない子に変更されずに渡されます。
    下記の例では、Alignで制約が緩めになり、赤色のContainerはStackFit.looseを受けています。

https://github.com/ling350181/flutter_ui/blob/main/lib/mult_child/stack_fit_page.dart

overflow

Flutter 2.10 以降、overflowは非推奨になり、ついに最新バージョンのdartには削除されることになりました。その代わりに、clipBehaviorの使用が推奨されています。

clipBehavior

クリップの動作です。Flex 、Wrap 、Stackでは同じ属性を持っています。

enum Clip {
  // なし、レイアウト領域を超えてもクリッピングしないことを意味します
  none, 
  // ハードエッジ。曲線パスでクリッピングするとギザギザが目立ちます。
  hardEdge, 
  // アンチエイリアシング、曲線パスがクリッピングする時、明らかなギザギザがなくなります
  antiAlias, 
  // アンチエイリアシング+ストレージ層
  antiAliasWithSaveLayer, 
}

clipBehavior