alpha Lounge

20%の技術記事とオタクネタ

【Flutter】マージンを等間隔に置けるRowウィジェット【小ネタ】

小ネタサンプルです。

Flutterを書いていて、縦のListViewの中に横にスクロールできるListViewを入れたい、となる時がよくあると思います。以下の図のような実装です。
この場合、横のListViewの高さを固定にする必要があります(viewportエラーが出ます)。

一方、Rowを使えばitemに合わせて高さを柔軟に変更してくれますが、ListViewのようにいい感じにitem間のマージンを空けるのが面倒です。
そこで、マージンを等間隔に置けるRow Widgetを書いてみました。

import 'package:flutter/material.dart';

class EvenlySpacedRow extends StatelessWidget {
  final List<Widget> children;
  final int edge;
  final int spacer;

  const EvenlySpacedRow({
    super.key,
    required this.children,
    required this.edge,
    required this.spacer,
  });

  List<Widget> _buildItem(Widget widget, int position, int length) {
    if (position == 0) {
      return <Widget>[
        SizedBox(
          width: edge.toDouble(),
        ),
        widget,
        SizedBox(
          width: spacer.toDouble(),
        ),
      ];
    } else if (position == length - 1) {
      return <Widget>[
        widget,
        SizedBox(
          width: edge.toDouble(),
        ),
      ];
    } else {
      return <Widget>[
        widget,
        SizedBox(
          width: spacer.toDouble(),
        ),
      ];
    }
  }

  @override
  Widget build(BuildContext context) {
    return SingleChildScrollView(
      scrollDirection: Axis.horizontal,
      child: Row(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: children
            .asMap()
            .entries
            .map((entry) {
          return _buildItem(entry.value, entry.key, children.length);
        })
            .expand((e) => e)
            .toList(),
      ),
    );
  }
}

使用例はこちら。

See the Pen Untitled by あるふぁ2048 (@alpha2048) on CodePen.

スクロール時の追加読み込みなどは実装してませんが、NotificationListenerなどを追加実装すれば実現できそうです。
そもそもListViewの高さを固定にすることでほとんど解決できるかと思いますが、困ったら使ってみてください。