Flutter入门进阶之旅(十四)ListView&GridView

在以前讲Layout Widget的文章中,咱们掌握了基于不一样的场景适当的选择不一样的Widget来完成咱们的布局要求,可是关于长列表的数据展现咱们并无作展开介绍,而长列表的身影几乎出如今平常生活中的任意一款APP中,鉴于它的重要性,因此我想单独做为一个章节来说解长列表Widget---ListView&GirdViewjava

1.ListView

1.1 ListView简单列表

看下ListView的构造方法,而后咱们用listview来完成一个简单列表缓存

ListView({
    Key key,
    Axis scrollDirection: Axis.vertical,//滚动方向
    bool reverse: false,//是否反向显示数据
    ScrollController controller,
    bool primary,
    ScrollPhysics physics,//物理滚动
    bool shrinkWrap: false,
    EdgeInsetsGeometry padding,
    this.itemExtent,//item有效范围
    bool addAutomaticKeepAlives: true,//自动保存视图缓存
    bool addRepaintBoundaries: true,//添加剧绘边界
    List<Widget> children: const <Widget>[],
  })
复制代码

ListView简单列表
上述效果图样例代码

import 'package:flutter/material.dart';

void main() {
  runApp(new MaterialApp(
    title: "ListView",
    home: new MyApp(),
  ));
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
        appBar: new AppBar(
          title: new Text("ListView"),
        ),
        body: ListView(
          scrollDirection: Axis.vertical, //控制列表方向
          children: <Widget>[
            new Container(
              width: 100.0,
              height: 100.0,
              color: Colors.lightBlue,
            ),
            new Container(
              width: 100.0,
              height: 100.0,
              color: Colors.red,
            ),
            new Container(
              width: 100.0,
              height: 100.0,
              color: Colors.deepPurple,
            ),
            new Container(
              width: 100.0,
              height: 100.0,
              color: Colors.yellow,
            ),
            new Container(
              width: 100.0,
              height: 100.0,
              color: Colors.lightBlue,
            ),
            new Container(
              width: 100.0,
              height: 100.0,
              color: Colors.red,
            ),
            new Container(
              width: 100.0,
              height: 100.0,
              color: Colors.deepPurple,
            ),
            new Container(
              width: 100.0,
              height: 100.0,
              color: Colors.lightBlue,
            ),
            new Container(
              width: 100.0,
              height: 100.0,
              color: Colors.red,
            ),
            new Container(
              width: 100.0,
              height: 100.0,
              color: Colors.deepPurple,
            ),
            new Container(
              width: 100.0,
              height: 100.0,
              color: Colors.lightBlue,
            ),
          ],
        ));
  }
}
复制代码

上述代码中咱们利用ListView作了一个简单的长列表布局,经过给children: <Widget>[]传入咱们要展现的子Widget来完成列表渲染,理论上咱们能够传入任意多的子Widget,可是这点使用起来跟Column没有太大差异,这显然是不符合咱们的预期的,由于咱们在使用ListView展现长列表布局的时候,大多数状况下咱们是不知道长列表一共有多少个元素,即便是能知道,咱们重复性的把每一个类似的布局都写一遍,也几乎让人崩溃。app

没错,Flutter确定给咱们提供了像原生Android写Adapter同样的方式,咱们能够提早写好公共的Item布局,而后经过ListView.builder()或者ListView.custom()方式自动生成长列表,ListView.builder()ListView.custom()的用法基本相同,只不过custom能够根据本身的须要控制Item显示方式,如Item显示大小。less

1.2 可复用的ListView长列表

下面我带你们一块儿看下ListView.builder()的构造方法,而后使用ListView.builder写个简单的样式代码,至于ListView.custom的用法我会在下面介绍GridView的时候讲到,读者可参考Listview.bulider自行测试。ide

ListView.builder({
    Key key,
    Axis scrollDirection: Axis.vertical,
    bool reverse: false,
    ScrollController controller,
    bool primary,
    ScrollPhysics physics,
    bool shrinkWrap: false,
    EdgeInsetsGeometry padding,
    this.itemExtent,
    @required IndexedWidgetBuilder itemBuilder,//item构建者
    int itemCount,//item数量
    bool addAutomaticKeepAlives: true,
    bool addRepaintBoundaries: true,
  })

复制代码

从ListView.bulider的构造方法咱们能够看出,它只比上述咱们直接使用的ListView的构造方法多了两个参数,也正是这两个参数简化了咱们对长列表的操做布局

itemCount::被展现的Item的数量 itemBuilder:被展现的Item的构造者(这里读者能够它类比成原生Android的Adapter)测试

下面咱们来看下效果图: ui

长列表
样例代码

import 'package:flutter/material.dart';

void main() {
  runApp(new MaterialApp(
    title: "ListView",
    home: new MyApp(),
  ));
}

class MyApp extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => MyState();
}

class MyState extends State {
  List<ItemEntity> entityList = [];

  @override
  void initState() {
    super.initState();
    for (int i = 0; i < 30; i++) {
      entityList.add(ItemEntity("Item $i", Icons.accessibility));
    }
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
        appBar: new AppBar(
          title: new Text("ListView"),
        ),
        body: ListView.builder(
          itemBuilder: (BuildContext context, int index) {
            return ItemView(entityList[index]);
          },
          itemCount: entityList.length,
        ));
  }
}

/** * 渲染Item的实体类 */
class ItemEntity {
  String title;
  IconData iconData;

  ItemEntity(this.title, this.iconData);
}

/** * ListView builder生成的Item布局,读者可类比成原生Android的Adapter的角色 */
class ItemView extends StatelessWidget {
  ItemEntity itemEntity;

  ItemView(this.itemEntity);

  @override
  Widget build(BuildContext context) {
    return Flex(
      direction: Axis.vertical,
      children: <Widget>[
        ListTile(
            leading: Icon(itemEntity.iconData), title: Text(itemEntity.title),subtitle: Text('长列表')),
        SizedBox(
          height: 0.2,
          child: Container(
            color: Colors.black,
          ),
        )
      ],
    );
  }
}
复制代码

上述代码中的逻辑读者大部分均可以自解的,我就很少作赘述了,下面咱们进入本篇分享的第二部分,关于GridView部分的讲解。this

2.GridView

跟原生Android同样,GridView知足了咱们全部使用表格布局的场景,固然若是GridView在每行或者每列都只显示一个Item的时候又至关于ListView的使用场景。可是回到Flutter上GridView的用法又跟ListView使用相似,能够直接new对象的方式生成简单的表格布局,也能够像ListView那样经过builder()和custom()方法来建立可复用的对象spa

构造方法

GridView({
    Key key,
    Axis scrollDirection: Axis.vertical,
    bool reverse: false,
    ScrollController controller,
    bool primary,
    ScrollPhysics physics,
    bool shrinkWrap: false,
    EdgeInsetsGeometry padding,
    @required this.gridDelegate,   //控制GridView显示方式
    bool addAutomaticKeepAlives: true,
    bool addRepaintBoundaries: true,
    List<Widget> children: const <Widget>[],
  })
复制代码

上面提到GridView跟ListView使用方法相似,可是GridView不一样于ListView的是它能够在一行或者一列显示多个Item,因此GridView的构造方法对比ListView多了一个gridDelegate参数,来配置一行(列)有几个Item和Item的间隔。

gridDelegate参数说明

gridDelegate可接收两种参数类型:

  • SliverGridDelegateWithFixedCrossAxisCount能够直接指定每行(列)显示多少个Item
  • SliverGridDelegateWithMaxCrossAxisExtent会根据GridView的宽度和你设置的每一个的宽度来自动计算没行显示多少个Item

先来看下GridView的效果图,关于gridDelegate的区别我在代码里作了注释讲解,这里就不在多赘述了读者可结合代码自行理解。

效果图

GridView
样例代码

import 'package:flutter/material.dart';

void main() {
  runApp(new MaterialApp(
    title: "ListView",
    home: new MyApp(),
  ));
}

class MyApp extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => MyState();
}
class MyState extends State {
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
        appBar: new AppBar(
          title: new Text("ListView"),
        ),
        body: new GridView(
// gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
// crossAxisCount: 3, //固定显示三个
// mainAxisSpacing: 10,
// crossAxisSpacing: 10),
          gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
              maxCrossAxisExtent: 100, //根据maxCrossAxisExtent的值对比屏幕的真实宽度,决定一行或者一列显示多少个Item
              mainAxisSpacing: 10,
              crossAxisSpacing: 10),
          children: <Widget>[
            Container(
                child: Icon(Icons.adb, size: 60),
                color: Colors.deepOrangeAccent),
            Container(
                child: Icon(Icons.adb, size: 60),
                color: Colors.deepOrangeAccent),
            Container(
                child: Icon(Icons.adb, size: 60),
                color: Colors.deepOrangeAccent),
            Container(
                child: Icon(Icons.adb, size: 60),
                color: Colors.deepOrangeAccent),
            Container(
                child: Icon(Icons.adb, size: 60),
                color: Colors.deepOrangeAccent),
            Container(
                child: Icon(Icons.adb, size: 60),
                color: Colors.deepOrangeAccent),
            Container(
                child: Icon(Icons.adb, size: 60),
                color: Colors.deepOrangeAccent),
            Container(
                child: Icon(Icons.adb, size: 60),
                color: Colors.deepOrangeAccent),
          ],
        ));
  }
}

复制代码

在本篇分享的第一部分咱们介绍ListView的时候提到,为了复用Item布局,咱们能够经过builder()或者custom来生成Item布局,在ListView中咱们使用的是builder()的方式生成的可复用的布局,在gridView中我带你们使用下custom(),其实listView跟GridView使用相似,无非就是布局排列不一样而已。

效果图

GridView

样例代码

import 'package:flutter/material.dart';

void main() {
  runApp(new MaterialApp(
    title: "ListView",
    home: new MyApp(),
  ));
}

class MyApp extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => MyState();
}

class MyState extends State {
  List<ItemEntity> entityList = [];

  @override
  void initState() {
    super.initState();
    for (int i = 0; i < 30; i++) {
      entityList.add(ItemEntity("Item $i", Icons.accessibility));
    }
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
        appBar: new AppBar(
          title: new Text("GridView"),
        ),
        body: GridView.custom(
            gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
              crossAxisCount: 3,
              crossAxisSpacing: 10,
              mainAxisSpacing: 10,
            ),
            childrenDelegate: SliverChildBuilderDelegate(
              (BuildContext context, int index) {
                return ItemView(entityList[index]);
              },
              childCount: entityList.length,
            )));
  }
}

/** * 渲染Item的实体类 */
class ItemEntity {
  String title;
  IconData iconData;

  ItemEntity(this.title, this.iconData);
}

/** * GridView builder生成的Item布局,读者可类比成原生Android的Adapter的角色 */
class ItemView extends StatelessWidget {
  ItemEntity itemEntity;

  ItemView(this.itemEntity);

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      child: Flex(
        direction: Axis.vertical,
        children: <Widget>[
          Icon(
            itemEntity.iconData,
            size: 60,
          ),
          Text(itemEntity.title),
        ],
      ),
      onTap: () {
        Scaffold.of(context).showSnackBar(
            new SnackBar(content: Text("点击了${itemEntity.title}")));
      },
    );
  }
}
复制代码

总结

经过本篇博文咱们了解到ListView跟GridView均可以直接用new对象的方式生成列表布局,一个用于表格布局,另外一个用于长列表布局,也可使用new 或者builder()和custom()方法来建立可复用对象,从而扩展了ListView跟GridView的灵活性,就像咱们原生Android同样,把可复用的布局抽象成Adapter的形式,可是或许你总以为关于列表还少点什么,下拉刷新?加载更多?

相关文章
相关标签/搜索