如何有条件地向列表中添加小部件?

49
在Flutter中,像Row/ListView/Stack这样的小部件不处理空子项。因此,如果我们想有条件地添加小部件作为子项,我通常会执行以下操作:
Row(
  children: <Widget>[
    foo == 42 ? Text("foo") : Container(),
  ],
);

但是添加一个空容器感觉很奇怪。

另一个解决方案是使用 where 过滤器:

Row(
  children: <Widget>[
    foo == 42 ? Text("foo") : null,
  ].where((t) => t != null).toList(),
);

这解决了空容器问题,但我们仍然有一个丑陋的三元运算符并且写起来很烦人。是否有更好的解决方案?
4个回答

89

编辑:

自Dart 2.2以来,新的语法本地支持此功能:

Column(
  children: [
    if (foo != null) Text(foo),
    Bar(),
  ],
);

这个问题目前正在 Github 上讨论,链接在此

但是现在,您可以使用 Dart 的 sync* 函数:

Row(
  children: toList(() sync* {
    if (foo == 42) {
      yield Text("foo");
    }
  }),
);

其中toList是:

typedef Iterable<T> IterableCallback<T>();

List<T> toList<T>(IterableCallback<T> cb) {
  return List.unmodifiable(cb());
}
不仅解决了条件添加问题,还可以通过yield*实现"展开操作符"。例如:
List<Widget> foo;

Row(
  children: toList(() sync* {
    yield Text("Hello World");
    yield* foo;
  }),
);

1
太棒了!List.of(_buildChildren())怎么样?其中_buildChildren是一个sync*方法。 - boformer
也可以使用。但是当您想要传递参数时,使用它会有点无聊。闭包使其更容易。 - Rémi Rousselet
我可以使用Dart 2.2语法来一次性添加多个符合条件的项吗? - nevermind

7
新的Dart语法允许在列表中使用'if',这导致了这个简单的解决方案:
Row(
  children: <Widget>[
    if (foo == 42) Text("foo"),
  ],
);

4

Row(
    children: [
        if (_id == 0) ...[
          Container()
        ] else if(_id == 1)...[
          Text("Hello")
        ] else ...[
          SizedBox(width: 20)
        ],
    ],
 ),


4

这是我使用的更简单的版本:

Row(
  children: [
    Text("always included"),
    skipNulls([
      icon,
      label,
    ]),
  ],
);

skipNulls<T>(List<T> items) {
  return items..removeWhere((item) => item == null);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接