🎃

[Flutter]if文switch文で表示するWidgetを変えようとするとエラーになる件

に公開

条件によって表示するWidgetを使い分けたかったのでif文switch文を使って実装しようとしたのですが、エラーが出ました。
原因と回避策を自分なりにまとめました。

エラーの状況

エラーの状況をわかりやすくするために、Flutterのサンプルコード(ボタンを押した回数を画面に表示するアプリ)を一部変えたもので見ていきます。

childの下に置いた場合

  body: Center(
    child: if(_counter % 2 == 0) {
            Text("偶数です");
          } else {
            Text("偶数です");
          },
  ),

エラーメッセージは以下の通り

// childの行に対して
Expected an identifier.
Expected to find ')'.

childrenの下に置いた場合

  body: Center(
    child: Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: <Widget>[
        const Text('ボタンを押した数が偶数か奇数か'),
        if(_counter % 2 == 0) {
          Text("偶数です");
        } else {
          Text("偶数です");
        },
      ],
    ),
  ),

エラーメッセージは以下の通り

// ifの行とelseの行に対して
The element type 'Set<Text>' can't be assigned to the list type 'Widget'.
Expected to find '}'.

エラーメッセージは原因を適切に反映してなさそう、、、

エラーの原因

Dartには値を返す「式(expression)」と、値を返さない「文(statement)」があり、式を受け取るchildに対して文を返しているためエラーとなるらしい。

調べたところそういうことらしいが正直これはいまいちピンと来なかった。

別の見方をすると、child、childrenにはWidget(を継承したUI部品、Row、Column、Textなど)を渡してやる必要があり、そこにWidgetではないif文をつっこんでいるためエラーを吐いている。

自分はこっちの考え方の方が理解できた。

回避策

ではWidgetの中で条件分岐を使いたい時はどうすればいいのか。
回避方法は以下の4通り

◼︎三項演算子

child: (value) ? Text("aaaaa") : Text("bbbbb")

この方法は2パターンの時しか使えない

◼︎関数を作成して呼び出す

child: judgeText(true),

Widget judgeText(bool value) {
    if (value) {
        return const Text("aaaaa");
    else {
        return const Text("bbbbb");
    }
}

◼︎即時関数

child: ((){
            if (value) {
                return const Text("aaaaa");
            } else {
                return const Text("bbbbb");
            })(),

◼︎スプレッド演算子

child: if(条件1)...[
            ウィジェットA,
        ]
        else if(条件2)...[
            ウィジェットB,
        ]
        else...[
            ウィジェットC,
        ],
children: [
        if(条件1)...[
            ウィジェットA,
        ]
        else if(条件2)...[
            ウィジェットB,
        ]
        else...[
            ウィジェットC,
        ],
]

個人的にはこの方法が一番シンプルで描きやすそう。

Discussion