【Flutter学习】基本组件之基本列表组件

时间:2019-06-21 11:27:19   收藏:0   阅读:130

一,概述

      列表是前端最常见的需求。 在flutter中,用ListView来显示列表页,支持垂直和水平方向展示,通过一个属性我们就可以控制其方向,列别有以下分类

二,构造函数
  构造方法有四种

三,参数解析

  • Key key
    • 解释:key值
  • Axis scrollDirection:Axis.vertical
    • 解释:ListView 的方向,为 Axis.vertical 表示纵向,为 Axis.horizontal 表示横向。
  • bool reverse:false
    • 解释:是否反向滚动
  • ScrollController controller
    • 解释:滑动监听,值为一个 ScrollController 对象,这个属性应该可以用来做下拉刷新和上垃加载
  • bool primary
    • 解释:是否是与父级PrimaryScrollController关联的主滚动视图。如果primary为true,controller必须设置
  • ScrollPhysics physics
    • 解释:
       设置 ListView 如何响应用户的滑动行为,值为一个 ScrollPhysics 对象,它的实现类常用的有:

          AlwaysScrollableScrollPhysics:总是可以滑动。
          NeverScrollableScrollPhysics:禁止滚动。
          BouncingScrollPhysics:内容超过一屏,上拉有回弹效果。
          ClampingScrollPhysics:包裹内容,不会有回弹,感觉跟 AlwaysScrollableScrollPhysics 差不多。

  • bool shrinkWrap:false 
    • 解释:多用于嵌套listView中 内容大小不确定 比如 垂直布局中 先后放入文字 listView (需要Expend包裹否则无法显示无穷大高度 但是需要确定listview高度 shrinkWrap使用内容适配不会有这样的影响)

  • EdgeInsetsGeometry padding
    • 解释:滚动视图与子项之间的内边距
  • double itemExtent
    • 解释:子项范围
  • required indexedWidgetBuilder
    • 解释:itemBuilder 位置构建器

  • int itemCount
    • 解释:子 Item 数量,只有使用 new ListView.builder() 和 new ListView.separated() 构造方法的时候才能指定,其中 new ListView.separated() 是必须指定。

  • bool addAutomaticKeepAlives:true
  • bool addRepaintBoundaries:true
  • bool addSemanticIndexes:true
  • double cacheExtent
  • child 
    • 解释:高度会适配 item填充的内容的高度,我们非常的不希望child的高度固定,因为这样的话,如果里面的内容超出就会造成布局的溢出。
  • int   semanticChildCount

四,示例demo
  

import package:flutter/material.dart;

//void main() => runApp(ListViewDemo());

class BaseBean {
  String name;
  int age;
  String content;

  BaseBean(this.name, this.age, this.content);
}

List<BaseBean> list = new List<BaseBean>.generate(
    60, (i) => new BaseBean("name$i", i, "content=$i"));

class ListViewDemo extends StatefulWidget {
  @override
  _ListViewDemoState createState() => new _ListViewDemoState();
}

class _ListViewDemoState extends State<ListViewDemo> {
  List<BaseBean> list;
  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    list = new List<BaseBean>.generate(
        60, (i) => new BaseBean("name$i", i, "content=$i"));
  }

  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
        home: new Scaffold(
            appBar: new AppBar(
              centerTitle: true,
              title: new Text("ListView"),
            ),
            body:
//            listViewDefault(list))
                listViewListTile(list))
//            listViewLayoutBuilder(list)),
//              listViewLayoutCustom(list)),
//              listViewLayoutSeparated(list)),
        );
  }

  ///默认构建
  Widget listViewDefault(List<BaseBean> list) {
    List<Widget> _list = new List();
    for (int i = 0; i < list.length; i++) {
      _list.add(new Center(
        child: new Text(list[i].age.toString()),
      ));
    }

// 添加分割线
    var divideList =
        ListTile.divideTiles(context: context, tiles: _list).toList();
    return new Scrollbar(
      child: new ListView(
        // 添加ListView控件
        children: _list, // 无分割线
//        children: divideList, // 添加分割线/
      ),
    );
  }

  /// ListTile
  Widget listViewListTile(List<BaseBean> list) {
    List<Widget> _list = new List();
    for (int i = 0; i < list.length; i++) {
      _list.add(new Center(
        child: ListTile(
          leading: new Icon(Icons.list),
          title: new Text(list[i].name),
          trailing: new Icon(Icons.keyboard_arrow_right),
        ),
      ));
    }
    return new ListView(
      children: _list,
    );
  }

  ///listView builder 构建
  Widget listViewLayoutBuilder(List<BaseBean> list) {
    return ListView.builder(
        //设置滑动方向 Axis.horizontal 水平  默认 Axis.vertical 垂直
        scrollDirection: Axis.vertical,
        //内间距
        padding: EdgeInsets.all(10.0),
        //是否倒序显示 默认正序 false  倒序true
        reverse: false,
        //false,如果内容不足,则用户无法滚动 而如果[primary]为true,它们总是可以尝试滚动。
        primary: true,
        //确定每一个item的高度 会让item加载更加高效
        itemExtent: 50.0,
        //item 高度会适配 item填充的内容的高度 多用于嵌套listView中 内容大小不确定 比如 垂直布局中 先后放入文字 listView (需要Expend包裹否则无法显示无穷大高度 但是需要确定listview高度 shrinkWrap使用内容适配不会) 文字
        shrinkWrap: true,
        //item 数量
        itemCount: list.length,
        //滑动类型设置
        //new AlwaysScrollableScrollPhysics() 总是可以滑动 NeverScrollableScrollPhysics禁止滚动 BouncingScrollPhysics 内容超过一屏 上拉有回弹效果 ClampingScrollPhysics 包裹内容 不会有回弹
//        cacheExtent: 30.0,  //cacheExtent  设置预加载的区域   cacheExtent 强制设置为了 0.0,从而关闭了“预加载”
        physics: new ClampingScrollPhysics(),
        //滑动监听
//        controller ,
        itemBuilder: (context, i) => new Container(
              child: new Row(
                mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                children: <Widget>[
                  new Text(
                    "${list[i].name}",
                    style: new TextStyle(fontSize: 18.0, color: Colors.red),
                  ),
                  new Text(
                    "${list[i].age}",
                    style: new TextStyle(fontSize: 18.0, color: Colors.green),
                  ),
                  new Text(
                    "${list[i].content}",
                    style: new TextStyle(fontSize: 18.0, color: Colors.blue),
                  ),
                ],
              ),
            ));
  }

  // ignore: slash_for_doc_comments
  /**
   * ListView({
      List<Widget> children,
      })

      ListView.builder({
      int: itemCount,
      IndexedWidgetBuilder itemBuilder,
      })

      ListView.custom({
      SliverChildDelegate childrenDelegate,
      })

      大家可能对前两种比较熟悉,分别是传入一个子元素列表或是传入一个根据索引创建子元素的函数。
      其实前两种方式都是第三种方式的“快捷方式”。因为 ListView 内部是靠这个 childrenDelegate 属性动态初始化子元素的。
   */

  ///listView custom 构建
  Widget listViewLayoutCustom(list) {
//    return ListView.custom(childrenDelegate: new MyChildrenDelegate());
    return ListView.custom(
      itemExtent: 40.0,
      childrenDelegate: MyChildrenDelegate(
        (BuildContext context, int i) {
          return new Container(
              child: new Row(
            mainAxisAlignment: MainAxisAlignment.spaceEvenly,
            children: <Widget>[
              new Text(
                "${list[i].name}",
                style: new TextStyle(fontSize: 18.0, color: Colors.red),
              ),
              new Text(
                "${list[i].age}",
                style: new TextStyle(fontSize: 18.0, color: Colors.green),
              ),
              new Text(
                "${list[i].content}",
                style: new TextStyle(fontSize: 18.0, color: Colors.blue),
              ),
            ],
          ));
        },
        childCount: list.length,
      ),
      cacheExtent: 0.0,
    );
  }
}

// ignore: slash_for_doc_comments
/**
 * 继承SliverChildBuilderDelegate  可以对列表的监听
 */
class MyChildrenDelegate extends SliverChildBuilderDelegate {
  MyChildrenDelegate(
    Widget Function(BuildContext, int) builder, {
    int childCount,
    bool addAutomaticKeepAlives = true,
    bool addRepaintBoundaries = true,
  }) : super(builder,
            childCount: childCount,
            addAutomaticKeepAlives: addAutomaticKeepAlives,
            addRepaintBoundaries: addRepaintBoundaries);

  ///监听 在可见的列表中 显示的第一个位置和最后一个位置
  @override
  void didFinishLayout(int firstIndex, int lastIndex) {
    print(firstIndex: $firstIndex, lastIndex: $lastIndex);
  }

  ///可不重写 重写不能为null  默认是true  添加进来的实例与之前的实例是否相同 相同返回true 反之false
  ///listView 暂时没有看到应用场景 源码中使用在 SliverFillViewport 中
  @override
  bool shouldRebuild(SliverChildBuilderDelegate oldDelegate) {
    // TODO: implement shouldRebuild
    print("oldDelegate$oldDelegate");
    return super.shouldRebuild(oldDelegate);
  }
}

///  listView separated 构建 用于多类型 分割
Widget listViewLayoutSeparated(List<BaseBean> list) {
  return ListView.separated(
    itemCount: list.length,
    separatorBuilder: (content, index) {
      //和itemBuilder 同级别的执行
      if (index == 2) {
        return new Container(
          height: 40.0,
          child: new Center(
            child: new Text("类型1"),
          ),
          color: Colors.red,
        );
      } else if (index == 7) {
        return new Container(
          height: 40.0,
          child: new Center(
            child: new Text("类型2"),
          ),
          color: Colors.blue,
        );
      } else if (index == 14) {
        return new Container(
          height: 40.0,
          child: new Center(
            child: new Text("类型3"),
          ),
          color: Colors.yellow,
        );
      } else {
        return new Container();
      }
    },
    itemBuilder: (content, i) {
      return new InkWell(
        child: new Container(
            height: 30.0,
            child: new Row(
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: <Widget>[
                new Text(
                  "${list[i].name}",
                  style: new TextStyle(fontSize: 18.0, color: Colors.red),
                ),
                new Text(
                  "${list[i].age}",
                  style: new TextStyle(fontSize: 18.0, color: Colors.green),
                ),
                new Text(
                  "${list[i].content}",
                  style: new TextStyle(fontSize: 18.0, color: Colors.blue),
                ),
              ],
            )),
        onTap: () {
          print("1111");
        },
      );
//      return ;
    },
  );
}

五,官方文档
  官方文档

原文:https://www.cnblogs.com/lxlx1798/p/11063520.html

评论(0
© 2014 bubuko.com 版权所有 - 联系我们:wmxa8@hotmail.com
打开技术之扣,分享程序人生!