概要
ボタンを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
: ボタンを押したときの挙動を指定する関数と,ボタンに表示するテキストのPair
のList
以下,例コード.
@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をうまく使って改造すると良いと思う.