0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

flutterでm行n列のgridボタンが欲しくなったから作った

Posted at

概要

ボタンをm行n列のgridで並べたくなったが,良い感じのコードが見当たらなかった.
生成系AI使ってもほしいものが手に入れられなかったので,なんとかして自作した.
需要がなんとなくあるかもしれないので共有する.

コード

コード内のコメントは生成系AIに書かせた.

// Pairクラスは2つの異なる型の値を保持するためのジェネリックなクラス
class Pair<T, U> {
  final T first;  // 最初の要素
  final U second; // 2番目の要素

  // コンストラクタでfirstとsecondを設定
  const Pair(this.first, this.second);

  // Pairのクローンを作成するメソッド
  Pair<T, U> clone() {
    // 新しいPairインスタンスを返す
    return Pair<T, U>(first, second);
  }
}

// MatrixGridは、行と列のマトリックス形式でボタンを表示するウィジェット
class MatrixGrid extends StatelessWidget {
  final int numberOfRow;  // 行数
  final List<Pair<VoidCallback?, String>> pairOfFuncAndText;  // 各ボタンに対応する関数とテキストのペア

  // コンストラクタ。numberOfRowとpairOfFuncAndTextを受け取る
  const MatrixGrid({super.key, required this.numberOfRow, required this.pairOfFuncAndText});

  @override
  Widget build(BuildContext context) {
    // pairOfFuncAndTextをクローンして新しいリストを作成(参照型のデータの変更を防ぐため)
    List<Pair<VoidCallback?, String>> _pairOfFuncAndText = pairOfFuncAndText.map((pair) => pair.clone()).toList();

    // リストの要素数が行数で割り切れない場合、足りない分の空のペアを追加
    for (int i = 0; i < pairOfFuncAndText.length % numberOfRow; ++i) {
      _pairOfFuncAndText.add(Pair(null, ''));  // 空のボタン用のペア
    }

    // 列数の計算。行数で割り切れる列数を決定
    int numberOfColumn = _pairOfFuncAndText.length ~/ numberOfRow;

    List<Widget> vertical_list = [];  // 縦方向のWidgetのリスト(列のリスト)

    // numberOfColumn分、列を作成
    for (int i = 0; i < numberOfColumn; ++i) {
      List<Widget> horizontal_list = [];  // 横方向のWidgetリスト(行のリスト)

      // 各列の行に対してボタンを作成
      for (int j = 0; j < numberOfRow; ++j) {
        int index = numberOfRow * i + j;  // 現在のボタンのインデックスを計算

        // ボタンを作成して横方向のリストに追加
        horizontal_list.add(
          Expanded(
            child: OutlinedButton(
              onPressed: _pairOfFuncAndText[index].first,  // ボタンが押されたときに実行される関数
              style: OutlinedButton.styleFrom(
                shape: RoundedRectangleBorder(
                  borderRadius: BorderRadius.zero,  // ボタンの角を四角に設定
                ),
                minimumSize: Size(double.infinity, double.infinity),  // ボタンを可能な限り広く
              ),
              child: Text(_pairOfFuncAndText[index].second),  // ボタンのテキスト
            ),
          ),
        );
      }

      // 横方向のボタンリストを縦方向のリストに追加
      vertical_list.add(
        Expanded(
          child: Row(
            mainAxisAlignment: MainAxisAlignment.center,  // 横方向に中央寄せ
            children: horizontal_list,  // 横方向のボタンリスト
          ),
        ),
      );
    }

    // 最後に、縦方向のリストをColumnでラップして中央に配置
    return Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,  // 縦方向に中央寄せ
        children: vertical_list,  // 縦方向のボタンリスト
      ),
    );
  }
}

使用例

MatricGridを使うのに必要なのは以下の2つ.

  • numberOfRow : 横方向に何個表示するのか
  • pairOfFuncAndText : ボタンを押したときの挙動を指定する関数と,ボタンに表示するテキストのPairList

以下,例コード.

@override
Widget build(BuildContext context) {
  // 横方向に何個表示するのか指定
  // 縦方向に表示する個数は自動で計算される
  const int numberOfRow = 2;

  // リストの長さはnumberOfRowで割り切れなくても良い
  // 勝手に無意味なボタンを追加してくれる
  final List<Pair<VoidCallback?, String>> pairOfFuncAndText = [Pair(null, 'ボタン1'), Pair(null, 'ボタン2'), Pair(null, 'ボタン3'), Pair(null, 'ボタン4'), Pair(null, 'ボタン5')];
  return MatrixGrid(numberOfRow: numberOfRow, pairOfFuncAndText: pairOfFuncAndText);
}

生成系AIをうまく使って改造すると良いと思う.

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?