一、应用场景

前面文章介绍了通过 Column 或者 Row + Expanded Widget 来实现 flex 布局,可以参考这篇文章:http://www.ptbird.cn/flutte-row-expanded-column.html#menu_index_6

但是 Row + Expanded 的实现方式有个致命问题是无法自动换行,而真正的 flex 布局是有一个 wrap 属性的,对于一行无法铺开的场景非常实用。

Flutter 针对这种场景提供了 Wrap widget,Wrap 的构造函数如下:

  Wrap({
    Key key,
    this.direction = Axis.horizontal,
    this.alignment = WrapAlignment.start,
    this.spacing = 0.0,
    this.runAlignment = WrapAlignment.start,
    this.runSpacing = 0.0,
    this.crossAxisAlignment = WrapCrossAlignment.start,
    this.textDirection,
    this.verticalDirection = VerticalDirection.down,
    List<Widget> children = const <Widget>[],
  }) : super(key: key, children: children);

从上面这个可以看出,Wrap 支持水平和垂直方向的布局,并且支持主轴和侧轴上布局设置

二、Wrap 基本应用

下面通过 Wrap 创建了一个比较典型的场景:标签列表

标签可能是长短都存在的,而且在布局中一般会透出多个标签

1、构造单个标签 widget

class ButtonItem extends StatelessWidget {
  ButtonItem({
    Key key,
    @required this.text,
  }) : super(key: key);

  final String text;

  @override
  Widget build(BuildContext context) {
    return RaisedButton(
      child: Text(this.text),
      color: Theme.of(context).buttonColor,
      onPressed: () {},
    );
  }
}

2、构造 Wrap 流式列表

标签存储在 _list,然后通过一个方法 _generateList 生成 List<Widget>,赋值给 Wrap 的 children 属性

class HomeContent extends StatelessWidget {
  List<String> _list = [
    '盗墓笔记',
    '鬼吹灯',
    '这个书名是凑的',
    '藏海花',
    '这个书名是凑的',
    '藏海花',
    '沙海',
    '藏海花',
    '这个书名是凑的',
    '藏海花'
  ];

  List<Widget> _generateList() {
    return _list.map((item) => ButtonItem(text: item)).toList();
  }

  @override
  Widget build(BuildContext context) {
    return Padding(
      child: Wrap(
        children: _generateList(),
        spacing: 12,
        runSpacing: 13,
        alignment: WrapAlignment.start,
        runAlignment: WrapAlignment.end,
      ),
      padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
    );
  }
}

3、结果:

58416-08tmp0f6n0aw.png

可以发现,一行中,会自动计算保证能够撑满,如果无法撑满,则会进行换行,上面图中可能看起来像是平均计算的宽度一样,实际上不是,如果更改一下字数,显示如下:

20326-2bttme0gztl.png

改变 aligment 的值,可以改变在主轴上的排列方式,类似 flex-direction, 比如我的赋值如下:

  @override
  Widget build(BuildContext context) {
    return Padding(
      child: Wrap(
        children: _generateList(),
        spacing: 12,
        runSpacing: 13,
        alignment: WrapAlignment.center,
      ),
      padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
    );
  }

36751-pl06scx478i.png

三、完整代码

https://github.com/postbird/FlutterHelloWorldDemo/blob/master/demo1/lib/bak/main.23-Wrap%20%20%E5%AE%9E%E7%8E%B0%E6%B5%81%E5%BC%8F%E5%B8%83%E5%B1%80.dart