Flutter(七)——多子元素组件:GridView,CustomScrollView,Flex,Wrap

前言

上一篇介绍了多元素组件:ListView,Scaffold,AppBar,Row,Column,这一节将接着上一篇博文,介绍GridView,CustomScrollView,Flex,以及Wrap多元素组件(下图为CustomScrollView实现效果)
CustomScrollView

GridView

首先,就是GridView,它和ListView相似,只不过表现形式为网格形式,可以把它看成Android的LayoutManager。如果GridView组件掌握的很好,那么App界面也是会非常好看,给人赏心悦目。不过需要注意的是,GridView中的gridDelegate属性,其类型是SliverGridDelegate,是一个抽象类,通过该类可以控制GridView的排列显示方式,我们先来看看官方文档的使用方式:

body: GridView.count(
        primary: false,
        padding: const EdgeInsets.all(20.0),
        crossAxisSpacing: 10.0,
        crossAxisCount: 2,
        children: <Widget>[
          const Text("11111111111111111111"),
          const Text("22222222222222222222"),
          const Text("33333333333333333333"),
          const Text("44444444444444444444"),
          const Text("55555555555555555555"),
          const Text("66666666666666666666"),
        ],
      ),

这里我们没有看到代码中使用SliverGridDelegate,那么它在哪里呢?其实,在GridView.count中的构造函数里已经传入了默认的gridDelegate,通过开发工具我们进入它的源码:

gridDelegate = SliverGridDelegateWithFixedCrossAxisCount(
         crossAxisCount: crossAxisCount,
         mainAxisSpacing: mainAxisSpacing,
         crossAxisSpacing: crossAxisSpacing,
         childAspectRatio: childAspectRatio,
       ),

源码里已经使用了SliverGridDelegateWithFixedCrossAxisCount。它有四个属性,我们先来看看他们的定义:

属性 取值
crossAxisCount 横向轴子元素的数量
mainAxisSpacing 横向轴之间的间距
crossAxisSpacing 子元素之间的间距
childAspectRatio 子元素的宽高比,比如2.0就表示宽度是高度的2倍

gridDelegate还支持SliverGridDelegateWithMaxCrossAxisExtent,同时GridView也和ListView一样支持GridView.builder来创建,使用代码与ListView差不多,这里就不在赘述了,上面代码实现效果如下:
GridView

CustomScrollView

在实际应用里,布局情况并不是非此即彼,一般一个界面不会只有一个滚动列表组件,很可能还有别的组件,这个时候CustomScrollView就有用处了,它的使用代码如下:

return CustomScrollView(
      slivers: <Widget>[
        const SliverAppBar(
          pinned: true,//标题栏是否固定
          expandedHeight: 250.0,//合并的高度,默认是状态栏的高度加AppBar的高度
          flexibleSpace: FlexibleSpaceBar(
            title: Text("我的标题"),
          ),
        ),
        SliverGrid(
            delegate: SliverChildBuilderDelegate((BuildContext context,int index){
              return Container(
                alignment: Alignment.center,
                color: Colors.teal[100*(index%9)],
                child: Text("第$index个"),
              );
            },childCount: 20),
            gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
                maxCrossAxisExtent: 200.0,//单个子Widget的水平最大宽度
                mainAxisSpacing: 10.0,//水平单个子Widget之间间距
                crossAxisSpacing: 10.0,//垂直单个子Widget之间间距
                childAspectRatio: 4.0,//宽高比
            )
        ),
        SliverFixedExtentList(
          itemExtent: 50.0,
          delegate: SliverChildBuilderDelegate((BuildContext context,int index){
            return Container(
              alignment: Alignment.center,
              color: Colors.lightBlue[100*(index%9)],
              child: Text("第$index个"),
            );
          }),
        ),
      ],
    );

这段代码看起来非常复杂其实很好理解,在Scaffold中,Appbar等价于SliverAppBar,刚讲解的GridView等价于SliverGrid,而ListView等价于SliverFixedExtentList,所以这是一个包含了二个滑动组件的一个布局容器,其他的代码中有注释,这里就不赘述了。(显示效果如博文首图)

特别注意:转换后的组件都是以“Sliver”开头的,其本身是不具备滚动特性的,但是放在CustomScrollView中之后,则可以实现滚动的功能。

Flex

Flex英文意思是屈伸,活动,在Flutter里面也就是弹性布局,该布局借鉴了前端里的Flex布局方式。用法也十分简单,我们可以在Flex中传入一些参数,其具体属性如下表:

属性 取值
direction Axis.vertical表示垂直方向,Axis.horizontal表示水平方向
flex 弹性系数,大于0会按比例来分割,等于0不会扩展占用的空间

可以把它理解为android:layout_weight属性,使用代码如下:

return Scaffold(
      appBar: AppBar(title: Text("Flex布局玩法"),),
      body: Column(
        children: <Widget>[
          Container(
            height: 400.0,
            child: Flex(
              direction: Axis.vertical,
              children: <Widget>[
                Expanded(
                  flex: 1,
                  child: Container(
                    color: Colors.red,
                  ),
                ),
                Expanded(
                  flex: 2,
                  child: Container(
                    color: Colors.yellow,
                  ),
                ),
              ],
            ),
          ),
          Container(
            height: 120.0,
            child: new Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: <Widget>[
                Expanded(
                  flex: 2,
                  child: Container(
                   color: Colors.blueAccent,
                  ),
                ),
                Expanded(
                  flex: 1,
                  child: Container(
                    color: Colors.red,
                  ),
                ),
              ],
            ),
          ),
        ],
      ),
    );

上面的例子中,我们实现了Flex布局。这种布局还有一种方式,它通过在Row组件里设置两边对齐也可以实现,代码显示效果如下:
Flex

Wrap

Wrap英文字面是包裹的意思,在前端开发中,我们通常把具有相同的布局整合在一个大的布局组件之内,比如说前面一节使用Row去包裹一些组件,因为它是多子元素组件,但是Row有时候会出问题,比如实际子组件超过屏幕,在这种情况下,我们就需要使用Wrap去代替Row组件,使用代码如下:

return Scaffold(
      appBar: AppBar(title: Text("Wrap组件玩法"),),
      body: Wrap(
        spacing: 4.0,
        runSpacing: 4.0,
        children: <Widget>[
          Container(
            color: Colors.yellow,
            child: Text("Python编程指南",style: new TextStyle(color: Colors.lightBlue),),
          ),
          Container(
            color: Colors.yellow,
            child: Text("Android编程指南",style: new TextStyle(color: Colors.lightBlue),)
          ),
          Container(
              color: Colors.yellow,
              child: Text("Flutter",style: new TextStyle(color: Colors.lightBlue),)
          ),
          Container(
              color: Colors.yellow,
              child: Text("VUE",style: new TextStyle(color: Colors.lightBlue),)
          ),
          Container(
              color: Colors.yellow,
              child: Text("Scaffold",style: new TextStyle(color: Colors.lightBlue),)
          ),
          Container(
              color: Colors.yellow,
              child: Text("Container",style: new TextStyle(color: Colors.lightBlue),)
          ),
          Container(
              color: Colors.yellow,
              child: Text("Colors",style: new TextStyle(color: Colors.lightBlue),)
          ),
          Container(
              color: Colors.yellow,
              child: Text("Colors.yellow",style: new TextStyle(color: Colors.lightBlue),)
          ),
        ],
      ),
    );

其实就是自适应控件布局容器,当一行放不下的时候会自动换行显示,这在Java开发中并没有配套的控件,需要自定义View,而Flutter开发中,直接提供了该组件,实现效果如下:
Wrap
多子元素组件到这里就全部讲解完成,下一篇博文将介绍Flutter状态管理。

发布了96 篇原创文章 · 获赞 129 · 访问量 83万+

猜你喜欢

转载自blog.csdn.net/liyuanjinglyj/article/details/104101218