Flutter 滑动列表组件 ListView&&GridView

这是我参与8月更文挑战的第5天,活动详情查看:8月更文挑战缓存

相关文章:Flutter listview下拉刷新 上拉加载更多 (juejin.cn)markdown

#前言: 今天就来介绍下Flutter中的列表组件ListView和网格组件GirdView,嗯,果真是Google家的亲儿子,连名字都和Android里的如出一辙。 好的吧,咱们仍是来看下这两个Widget的用法吧app


#ListView ListView就是咱们常见的列表组件,在平时的应用开发中十分的常见,不管你作的是什么类型的应用都会多多少少会用到ListView,因此要好好看下这篇文章哦less

仍是先来看下listView的构造方法:ide

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>[],
})
复制代码

那么,咱们仍是来看下具体的用法oop

咱们仍是按照惯例在Scaffold里放一个ListViewpost

import 'package:flutter/material.dart';

class Routes extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('目录')),
      body: new ListView(
        children: <Widget>[
          ListTile(
            title: Text('标题1'),
            leading: Icon(Icons.build),
            trailing: Text('尾巴'),
            onTap: () {
              showDialog(
                  context: context,
                  child: new SimpleDialog(
                    contentPadding: const EdgeInsets.all(10.0),
                    title: new Text("我是标题"),
                    children: <Widget>[new Text("我是内容区域")],
                  ));
            },
          ),
          ListTile(
            title: Text('标题2'),
            leading: Icon(Icons.print),
            trailing: Text('尾巴'),
          ),
          ListTile(
            title: Text('标题3'),
            leading: Icon(Icons.library_music),
            trailing: Text('尾巴'),
          ),
          ListTile(
            title: Text('标题4'),
            leading: Icon(Icons.accessibility_new),
            trailing: Text('尾巴'),
          ),
        ],
      ),
    );
  }
}

复制代码

children参数咱们传入了4个ListTile,先介绍下: ListTile是一个固定高度的行,一般包含一些文本,以及一个行前或行尾图标。测试

const ListTile({
    Key key,
    this.leading,
    this.title,
    this.subtitle,
    this.trailing,
    this.isThreeLine = false,
    this.dense,
    this.contentPadding,
    this.enabled = true,
    this.onTap,
    this.onLongPress,
    this.selected = false,
  }) : assert(isThreeLine != null),
       assert(enabled != null),
       assert(selected != null),
       assert(!isThreeLine || subtitle != null),
       super(key: key);
       
复制代码

而后咱们来看下效果 ![这里写图片描述] (img-blog.csdn.net/20180905161…)ui

固然,因为数据量过少它如今是不能滑动的。你们能够在下面多加几个Widget试试效果。this

在Flutter中有三种构建ListView的方式,刚才介绍的是最简单的一种,可是却不是最经常使用的,由于它仅仅适用于已知数量或者较少数量的Item的状况。若是有未知数量或者无限个Item的状况,再使用上述的方法将再也不适用。

那么,咱们能够尝试下ListView.builder()ListView.custom()

ListView.builder()和ListView.custom()的用法基本相同,只不过custom能够根据本身的须要控制Item显示方式,如Item显示大小。

咱们今天来看下ListView.builder()

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,
    double cacheExtent,
  }) 
复制代码

相比于new ListView()只不过多出了两个参数而已,一个是itemCount指定item的数量,一个是itemBuilder,用来构建Item。

看下用法

import 'package:flutter/material.dart';

class ListItem {
  final String title;
  final IconData iconData;

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

class ListItemWidget extends StatelessWidget {
  final ListItem listItem;

  ListItemWidget(this.listItem);

  @override
  Widget build(BuildContext context) {
    return new ListTile(
      leading: new Icon(listItem.iconData),
      title: new Text(listItem.title),
    );
  }
}

class Routes extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return RouteState();
  }
}

class RouteState extends State<Routes> {
  final List<ListItem> listData = [];

  @override
  void initState() {
    super.initState();
    for (int i = 0; i < 20; i++) {
      listData.add(ListItem("我是测试标题$i", Icons.cake));
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('列表'),
      ),
      body: ListView.builder(
        itemBuilder: (BuildContext context, int index) {
          return ListItemWidget(listData[index]);
        },
        itemCount: listData.length,
      ),
    );
  }
}
复制代码

咱们首先新建了一个ListItem对象,icon和title两个属性 咱们新建了一个一个Widget,须要传入ListItem对象,借助于ListItem对象的属性初始化ListTitle。 而后在initState方法中初始化listData,建立了20个ListItem对象。

在itemBuilder中返回指定的的Listitem到ListItemWidget对象中,返回指定的ListItemWidget对象。

经过这种方法,咱们不须要关注Item的数量,由于咱们每一个Item都是自动构建的,而且大大减小重复代码的数量。 这里写图片描述 下面来看下GridView


#GridView GirView的用法和ListView相似,只不过因为GridView能够在一列或者一行显示多个Item,因此在构造方法中就多了个参数

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,
    double cacheExtent,
    List<Widget> children = const <Widget>[],
  })
  
复制代码

看下gridDelegate参数

能够传入SliverGridDelegateWithFixedCrossAxisCount对象和SliverGridDelegateWithMaxCrossAxisExtent对象。 其中SliverGridDelegateWithFixedCrossAxisCount能够直接指定每行(列)显示多少个Item,SliverGridDelegateWithMaxCrossAxisExtent会根据GridView的宽度和你设置的每一个的宽度来自动计算没行显示多少个Item 国际惯例,咱们仍是只介绍一个,那就SliverGridDelegateWithFixedCrossAxisCount吧。

看下代码,怎么用

import 'package:flutter/material.dart';

class GridViewPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('GridView'),
      ),
      body: GridView(
        gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
            crossAxisCount: 2, //每行2个
            mainAxisSpacing: 10.0, //主轴(竖直)方向间距
            crossAxisSpacing: 10.0, //纵轴(水平)方向间距
            childAspectRatio: 1.0 //纵轴缩放比例
            ),
        children: <Widget>[
          Container(
            alignment: Alignment.center,
            color: Colors.green,
            child: Image.asset("images/pic1.jpg"),
          ),
          Container(
            alignment: Alignment.center,
            color: Colors.green,
            child: Image.asset("images/pic1.jpg"),
          ),
          Container(
            alignment: Alignment.center,
            color: Colors.green,
            child: Image.asset("images/pic1.jpg"),
          ),
          Container(
            alignment: Alignment.center,
            color: Colors.green,
            child: Image.asset("images/pic1.jpg"),
          ),
          Container(
            alignment: Alignment.center,
            color: Colors.green,
            child: Image.asset("images/pic1.jpg"),
          ),
          Container(
            alignment: Alignment.center,
            color: Colors.green,
            child: Image.asset("images/pic1.jpg"),
          ),
          Container(
            alignment: Alignment.center,
            color: Colors.green,
            child: Image.asset("images/pic1.jpg"),
          ),
        ],
      ),
    );
  }
}

复制代码

和ListView相似,咱们在GridView的children中新增了7个图片并给它设置背景并居中,另外咱们根据gridDelegate属性设置每行显示2个Item,而且设置Item间隔为10像素。

效果以下: 这里写图片描述 固然,GridView你也可使用builder()和custom()的方式实现

import 'package:flutter/material.dart';

class GridViewPage extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return GridViewState();
  }
}

class GridViewState extends State<GridViewPage> {
  final List<ListItem> listData = [];

  @override
  void initState() {
    super.initState();
    for (int i = 0; i < 20; i++) {
      listData.add(new ListItem("我是测试标题$i", Icons.cake));
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('GridView'),
      ),
      body: GridView.builder(
        gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
            crossAxisCount: 2, //每行2个
            mainAxisSpacing: 10.0, //主轴(竖直)方向间距
            crossAxisSpacing: 10.0, //纵轴(水平)方向间距
            childAspectRatio: 1.0 //纵轴缩放比例
            ),
        itemCount: listData.length,
        itemBuilder: (BuildContext context, int index) {
          return ListItemWidget(listData[index]);
        },
      ),
    );
  }
}

class ListItem {
  final String title;
  final IconData iconData;

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

class ListItemWidget extends StatelessWidget {
  final ListItem listItem;

  ListItemWidget(this.listItem);

  @override
  Widget build(BuildContext context) {
    return new GestureDetector(
      child: new Container(
        color: Colors.green,
        child: new Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            new Icon(
              listItem.iconData,
              size: 50.0,
              color: Colors.white,
            ),
            new Text(
              listItem.title,
              style: TextStyle(color: Colors.white),
            )
          ],
        ),
      ),
      onTap: () {
        Scaffold.of(context).showSnackBar(new SnackBar(
          content: new Text(listItem.title),
        ));
      },
    );
  }
}

复制代码

和上面ListView的用相似,只不过咱们如今是一行显示多个Item而已。而且咱们给每一个Item设置上了点击事件,每次点击Item就会弹出相应的标题。 这里写图片描述


##小结

  • ListView就是咱们经常使用的列表视图

  • GridView就是咱们经常使用的宫格视图

  • ListView和GridView均可以使用new 或者builder()和custom()方法来建立对象

相关文章
相关标签/搜索