52
31

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Flutter で動的に Widget の表示・非表示を制御する方法まとめ

Last updated at Posted at 2020-04-26

Flutterで条件によってWidgetの表示・非表示を切り替える方法を調べていたらいくつかありそうなのでまとめました。
間違いや気になるところあれば指摘していただけると嬉しいです :pray:

結論

if (Control Flow Collections) を使うのがシンプルで良さそう。

使用例
Column(
  children: <Widget>[
    if (showHoge) Text('hoge'),
    Text('fuga'),
  ],
),

Dart2.3 で導入された機能だそうです。
Widget ツリーに限らず配列に含めるかどうかを if で制御できます。
ちなみに elseelse if も使えます。

参考: https://github.com/dart-lang/language/blob/master/accepted/2.3/control-flow-collections/feature-specification.md

※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

52
31
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
52
31

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?