Flutterで条件によってWidgetの表示・非表示を切り替える方法を調べていたらいくつかありそうなのでまとめました。
間違いや気になるところあれば指摘していただけると嬉しいです
結論
if (Control Flow Collections) を使うのがシンプルで良さそう。
Column(
children: <Widget>[
if (showHoge) Text('hoge'),
Text('fuga'),
],
),
Dart2.3 で導入された機能だそうです。
Widget ツリーに限らず配列に含めるかどうかを if
で制御できます。
ちなみに else
や else if
も使えます。
※pubspec.yaml で sdk を 2.3.0 以上に指定する必要があります。
その他候補
Visibility
Column(
children: <Widget>[
Visibility(
visible: showHoge,
child: Text('hoge'),
),
Text('fuga'),
],
),
そのものって感じな Widget ですね。
プロパティによって非表示時に領域を確保することもできます。
しかし、ドキュメントには「ただ Widget を隠すだけなら Visibility を使う必要はありません。要素を含めないのが一番シンプルです」みたいなことが書かれているので、そのまんま鵜呑みにすると、非表示にするだけなら if を使うのが良いかも。
Using this widget is not necessary to hide children. The simplest way to hide a child is just to not include it, or, if a child must be given (e.g. because the parent is a StatelessWidget) then to use SizedBox.shrink instead of the child that would otherwise be included.
参考: https://api.flutter.dev/flutter/widgets/Visibility-class.html
三項演算子 + SizedBox.shrink
Column(
children: <Widget>[
(showHoge) ? Text('hoge') : SizedBox.shrink(),
Text('fuga'),
],
),
調べる前はこの方法で実装しようとしていました。
空っぽを示す SizedBox.shrink()
をわざわざ書くのが少し気持ち悪いので、先述の候補の方が良いと思っています。
※余談①
もし「showHoge == false
なら別の Widget を表示する」場合、三項演算子でも if-else でも同じことができます。その場合は三項演算子を使うのが個人的には好みなんですが...Control Flow Collections の仕様の中では三項演算子読みづらくない?って言われちゃってますね。
Users can and do use the conditional operator
(?:)
for cases like this today. It works OK, but isn't very easy on the eyes. And, of course, it falls down in cases where you don't have an "else" widget that you want to use instead of the "then" one.
https://github.com/dart-lang/language/blob/master/accepted/2.3/control-flow-collections/feature-specification.md
※余談②
空の状態を示すWidgetを表現する場合、nullだとエラーになるのでどうするか?について。実装例とかで Container()
をよく見かける気がしますがレイアウトに影響を与えることがあるので SizedBox.shrink()
を使うようにしています。
参考: https://stackoverflow.com/a/55796929
その他
Visibility のドキュメントを読むと以下の Widget で部分的に似たようなことをできるようですね。
if や Visibility では要求を叶えられない場合に助けになるかもしれません。
These widgets provide some of the facets of this one:
- Opacity, which can stop its child from being painted.
- Offstage, which can stop its child from being laid out or painted.
- TickerMode, which can stop its child from being animated.
- ExcludeSemantics, which can hide the child from accessibility tools.
- IgnorePointer, which can disable touch interactions with the child.
あと、アニメーションと共に表示・非表示する場合は Animated
系の Widget が使えますね。
- AnimatedSwitcher, which can fade from one child to the next as the subtree changes.
- AnimatedCrossFade, which can fade between two specific children.
https://api.flutter.dev/flutter/widgets/Visibility-class.html
まとめ
結論に書いた通り基本的には if が良さそう。
チームの好みや要件次第では Visibility も良さそうですね。
参考
dart - Show/hide widgets in Flutter programmatically - Stack Overflow
https://stackoverflow.com/a/53044562