はじめに
FlutterでWidgetをList配列でループさせて表示させようと無邪気にfor文を使うとまんまとエラーになり、ハマるので簡単な解決方法をメモします。
Dart言語で用意されているスプレッド演算子(...)を使ってFlutterで動的にWidgetを作成することができます。
(スプレッド演算子を使うことでスタイリッシュに記述できます)
無邪気にfor文でList配列をループさせてみる
List配列を用意します
List<Widget> textWidgets() {
return [
Text('hogehoge1'),
Text('hogehoge2'),
Text('hogehoge3'),
];
}
List配列をforループさせて実行させます
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('With Spread Operator'),
),
body: Column(
children: [
for(int i = 0; i < textWidgets().length; i++) {
textWidgets()[i]
}
],
),
),
);
}
}
実行結果
コンパイルエラーになります
Error: A value of type 'Set<Widget>' can't be assigned to a variable of type 'Widget'.
## 原因
Flutterでは動的にWidgetを配置する場合にはfor文を純粋に使うだけではうまくいきません。(これはFlutterの仕様でそうなっています)
解決策1:スプレッド演算子を使う(for{}...)
for{}...でスプレッド演算子を使って動的に表示することができます(下記コードはエラーにならず、うまく表示されます。)
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('With Spread Operator'),
),
body: Column(
children: [
for(int i = 0; i < textWidgets().length; i++) ...{
textWidgets()[i]
}
],
),
),
);
}
}
解決策2:スプレッド演算子を使う(Listに...)
そのままListにスプレッド演算子を使うこともできます。(下記コードはエラーにならず、うまく表示されます。)
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('With Spread Operator'),
),
body: Column(
children: [
...textWidgets()
],
),
),
);
}
}
解決策3:スプレッド演算子を使う(...[]for(){})
配列にスプレッド演算子を使って動的に表示することができます(下記コードはエラーにならず、うまく表示されます。)
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('With Spread Operator'),
),
body: Column(
children: [
...[
for(int i = 0; i < textWidgets().length; i++) textWidgets()[i],
]
],
),
),
);
}
}
スプレッド演算子を使わない場合
基本的に動的にWidgetを表示する方法はスプレッド演算子を使う方法しかFlutterはなさそうです。そもそも連続して表示する場合のコンテンツとしてListViewやGridViewなどがあるためそれで大概は解決します。しかしプログラムして同類のコンテンツをループさせたいシチュエーションはあるためその時のために覚えておくと便利です。
スプレッド演算子を使わない方法
- for文を使わずにそのまま配列のWidgetをインデックスを指定して表示する
- ListViewなどを使って動的に表示する
さいごに
Flutterも然り、宣言型UIのプログラムはレイアウトとロジックを組み合わせる仕組み上、どうしても独特のルールが存在します。SwiftUI,JetpackComposeも同様にそれぞれ強めのルールがあるため個別にルールとして記憶して対応するのが良いでしょう。(内部的に深く追求するのもいいと思います。)