Flutter学习7-列表ListView用法(横向滚动,下拉刷新,上拉加载)

·  阅读 1977

ListView是Flutter中的列表组件,可以横向也可以垂直

ListView 常见用法

ListView 横向滚动和垂直滚动

这部分还是直接写代码吧

class ListPageState extends State<ListPage> {
  bool isVertical = true;
  var list = ['上海','北京','深圳','天津','邯郸',];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('测试ListView'),
      ),
      body: ListView(
      //通过该属性,设置朝向是垂直还是横向
        scrollDirection: isVertical ? Axis.vertical : Axis.horizontal,
        children: [
          RaisedButton(
            onPressed: () {
              setState(() {
                isVertical = !isVertical;
              });
            },
            child: Text('点我切换方向'),
          ),
          ...buildListItem()
        ],
      ),
    );
  }

  List<Widget> buildListItem() {
    return list
        .map((e) => isVertical ? _buildVItem(e) : _buildHItem(e))
        .toList();
  }
//构建纵向列表item
  Widget _buildVItem(String cityNam) {
    return Container(
      margin: EdgeInsets.only(bottom: 5),
      padding: EdgeInsets.only(top: 10, bottom: 10),
      alignment: Alignment.center,
      decoration: BoxDecoration(color: Colors.green),
      child: Text(
        '$cityNam',
        style: TextStyle(
            fontSize: 20,
            fontWeight: FontWeight.bold,
            color: Colors.tealAccent),
      ),
    );
  }
//构建横向item
  Widget _buildHItem(String cityNam) {
    return Container(
      width: 100,
      height: 100,
      margin: EdgeInsets.only(right: 5),
      padding: EdgeInsets.only(right: 10, left: 10),
      alignment: Alignment.center,
      decoration: BoxDecoration(color: Colors.green),
      child: Text(
        '$cityNam',
        style: TextStyle(
            fontSize: 20,
            fontWeight: FontWeight.bold,
            color: Colors.tealAccent),
      ),
    );
  }
}
复制代码

效果

需要注意的是ListView横向滚动时,设置item高度是不生效的,可以设置ListView的父布局高度,进行高度控制

ListView.builder()

这是一种简便的构建ListView方式 将上面的代码简单替换即可

      body: ListView.builder(
          itemCount: list.length,
          scrollDirection: Axis.vertical,
          itemBuilder: (BuildContext context, int index) {
            return _buildVItem(list[index]);
          }),
复制代码

可折叠的List(ExpansionTile)

实现类似QQ里面联系人分组的界面,可以使用ExpansionTile实现

class ExpandPage extends StatefulWidget {
  @override
  State<ExpandPage> createState() {
    return ExpandPageState();
  }
}

class ExpandPageState extends State<ExpandPage> {
  var list = {
    '中国': ['上海', '北京', '深圳', '天津', '邯郸',],
    'China': ['上海', '北京', '深圳', '天津', '邯郸',],
    'CN': ['上海', '北京', '深圳', '天津', '邯郸',]
  };

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('测试可展开的ListView'),
      ),
      body: ListView.builder(
          itemCount: list.keys.length,
          scrollDirection: Axis.vertical,
          itemBuilder: (BuildContext context, int index) {
            return _buildVItem(index);
          }),
    );
  }

  Widget _buildVItem(int index) {
    String countyName = list.keys.elementAt(index);
    var listCity = list[countyName];
    return ExpansionTile(
      leading: Icon(Icons.agriculture),
      subtitle: Text("副标题"),
      title: Text(
        countyName,
        style: TextStyle(fontSize: 20, color: Colors.teal),
      ),
      children: _buildExpandItem(listCity),
    );
  }

  List<Widget> _buildExpandItem(List<String> listCity) {
    return listCity
        .map((e) => FractionallySizedBox(
              widthFactor: 1,
              child: Container(
                padding: EdgeInsets.only(top: 10, bottom: 10),
                decoration: BoxDecoration(color: Colors.pink),
                child: Text(
                  e,
                  style: TextStyle(fontSize: 18, color: Colors.white),
                ),
              ),
            ))
        .toList();
  }
}
复制代码

效果

也可以使用ExpansionPanelList实现

GridView 网格布局

Flutter中实现网格布局使用GridView实现

  • scrollDirection 控制GridView方向
  • gridDelegate 控制GridView的字widget的创建方式,主轴和交叉轴方向的间距以及子widget的宽高比
  • child 是子widget的list,注意改list中的widget设置的宽高是不生效的,子widget的宽高比已经由 gridDelegate 控制了
class GridPage extends StatefulWidget {
  @override
  State<GridPage> createState() {
    return GridPageState();
  }
}

class GridPageState extends State<GridPage> {
  bool isVertical = true;
  var list = [
    '上海',
    '北京',
    '深圳',
    '天津',
    '邯郸',
  ];
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('测试GridView'),
      ),
      body: GridView(
        padding: EdgeInsets.all(0),//边距
        scrollDirection: Axis.vertical,//是垂直滚动还是横向滚动
        //GridView的子Item的创建方式
        //SliverGridDelegateWithFixedCrossAxisCount :交叉轴上子widget的数量创建方式
        //SliverGridDelegateWithMaxCrossAxisExtent:主轴上固定宽或高的创建方式
        gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
            crossAxisCount: 4,//交叉轴上子widget的数量,
            mainAxisSpacing: 1,//主轴方向上子widget之间的间距
            crossAxisSpacing: 1,//交叉轴方向上子widget之间的间距
            childAspectRatio: 1),//子widget的交叉轴/主轴,它是宽高比或者高宽比
        children: buildListItem(),
      ),
      // body: GridView(
      //   padding: EdgeInsets.zero,
      //   scrollDirection: Axis.vertical,
      //   gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
      //       maxCrossAxisExtent: 240,//交叉轴方向上最大宽或高
      //       crossAxisSpacing: 1,
      //       childAspectRatio: 2,
      //       mainAxisSpacing: 1),
      //   children: buildListItem(),
      // ),
    );
  }

  List<Widget> buildListItem() {
    return list.map((e) => _buildVItem(e)).toList();
  }

  Widget _buildVItem(String cityNam) {
    return Container(
      padding: EdgeInsets.only(top: 10, bottom: 10),
      alignment: Alignment.center,
      decoration: BoxDecoration(color: Colors.green),
      child: Text(
        '$cityNam',
        style: TextStyle(
            fontSize: 20,
            fontWeight: FontWeight.bold,
            color: Colors.tealAccent),
      ),
    );
  }
}
复制代码

效果

RefreshIndicator 下拉刷新组件

RefreshIndicator 是Flutter官方提供的下拉刷新组件,RefreshIndicator搭配ListView或GridView的时候 方向必须是垂直滚动的,横向的无效的,

RefreshIndicator构造分析

  • onRefresh 必要参数,是返回值类型为Future的回调Future Function(),当用户下拉组件时会回调到该方法中,这个时候一般会进行http请求,数据库读写等操作,
  • child 下拉刷新的子widget,一般为ListView或CustomScrollView
//模拟两秒后返回数据
  Future<Null> _handRefresh() async{
    await Future.delayed(Duration(seconds: 2));
    setState(() {
      list=list.reversed.toList();
    });
  }
复制代码

ListView 中

GridView中

列表加载更多

Flutter官方并没有像refresh下拉刷新那样提供组件,需要通过监听列表滚动的距离是否到底部手动触发加载更多,

  1. 自定义ScrollController
  ScrollController _scrollController;

  @override
  void initState() {
    super.initState();
    _scrollController = ScrollController();
    _scrollController.addListener(() {
      if (_scrollController.position.pixels == _scrollController.position.maxScrollExtent) {
        print("开始加载更多");
        _handLoadMore();
      }
    });
  }
复制代码
  1. 触发加载更多
 _handLoadMore() async {
    await Future.delayed(Duration(seconds: 15));
    setState(() {
      var newData = List<String>.from(list);
      list.addAll(newData);
    });
  }
复制代码
  1. 将Scroller设置给ListView
ListView( controller: _scrollController,XXX)
复制代码

如果上下反复滚动会多次触发该方法,需要自定义状态进行加载更多的控制

分类:
Android
标签:
收藏成功!
已添加到「」, 点击更改