Flutter 基本组件ListlView

Flutter 列表组件

列表布局是我们项目开发中最常用的一种布局方式。Flutter 中我们可以通过 ListView 来定义 列表项,支持垂直和水平方向展示。通过一个属性就可以控制列表的显示方向。列表有一下 分类:
1.垂直列表
2.垂直图文列表
3.水平列表
4.动态列表
5.矩阵式列表

构造方法

方法一
默认构造函数采用子类的显式。此构造函数适用于具有少量(有限个)子项的列表视图,因为构造List需要为可能在列表视图中显示的每个子项执行工作,而不仅仅是那些实际可见的子项

class ListView extends BoxScrollView {
  /// Creates a scrollable, linear array of widgets from an explicit [List].
  ///
  /// This constructor is appropriate for list views with a small number of
  /// children because constructing the [List] requires doing work for every
  /// child that could possibly be displayed in the list view instead of just
  /// those children that are actually visible.
  ///
  /// It is usually more efficient to create children on demand using [new
  /// ListView.builder].
  ///
  /// The `addAutomaticKeepAlives` argument corresponds to the
  /// [SliverChildListDelegate.addAutomaticKeepAlives] property. The
  /// `addRepaintBoundaries` argument corresponds to the
  /// [SliverChildListDelegate.addRepaintBoundaries] property. The
  /// `addSemanticIndexes` argument corresponds to the
  /// [SliverChildListDelegate.addSemanticIndexes] property. None
  /// may be null.
  ListView({
    Key key,
    Axis scrollDirection = Axis.vertical,
    bool reverse = false,
    ScrollController controller,
    bool primary,
    ScrollPhysics physics,
    bool shrinkWrap = false,
    EdgeInsetsGeometry padding,
    this.itemExtent,
    bool addAutomaticKeepAlives = true,
    bool addRepaintBoundaries = true,
    bool addSemanticIndexes = true,
    double cacheExtent,
    List children = const [],
    int semanticChildCount,
    DragStartBehavior dragStartBehavior = DragStartBehavior.start,
  }) : childrenDelegate = SliverChildListDelegate(
         children,
         addAutomaticKeepAlives: addAutomaticKeepAlives,
         addRepaintBoundaries: addRepaintBoundaries,
         addSemanticIndexes: addSemanticIndexes,
       ),
       super(
         key: key,
         scrollDirection: scrollDirection,
         reverse: reverse,
         controller: controller,
         primary: primary,
         physics: physics,
         shrinkWrap: shrinkWrap,
         padding: padding,
         cacheExtent: cacheExtent,
         semanticChildCount: semanticChildCount ?? children.length,
         dragStartBehavior: dragStartBehavior,
       );

方法二
它构造函数采用IndexedWidgetBuilder它根据需要构建子项。此构造函数适用于具有大量(或无限)子项数的列表视图,因为仅为实际可见的子项调用构建器。
长列表时采用builder模式,能提高性能。不是把所有子控件都构造出来,而是在控件viewport加上头尾的cacheExtent这个范围内的子Item才会被构造。在构造时传递一个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,
    int itemCount,
    bool addAutomaticKeepAlives = true,
    bool addRepaintBoundaries = true,
    bool addSemanticIndexes = true,
    double cacheExtent,
    int semanticChildCount,
    DragStartBehavior dragStartBehavior = DragStartBehavior.start,
  }) : childrenDelegate = SliverChildBuilderDelegate(
         itemBuilder,
         childCount: itemCount,
         addAutomaticKeepAlives: addAutomaticKeepAlives,
         addRepaintBoundaries: addRepaintBoundaries,
         addSemanticIndexes: addSemanticIndexes,
       ),
       super(
         key: key,
         scrollDirection: scrollDirection,
         reverse: reverse,
         controller: controller,
         primary: primary,
         physics: physics,
         shrinkWrap: shrinkWrap,
         padding: padding,
         cacheExtent: cacheExtent,
         semanticChildCount: semanticChildCount ?? itemCount,
         dragStartBehavior: dragStartBehavior,
       );

方式三
它的构造函数有两个IndexedWidgetBuilder 构建器: itemBuilder根据需要构建子项,separatorBuilder 类似地构建出现在子项之间的分隔子项。此构造函数适用于具有固定数量子项的列表视图。
列表中需要分割线时,可以自定义复杂的分割线

ListView.separated({
    Key key,
    Axis scrollDirection = Axis.vertical,
    bool reverse = false,
    ScrollController controller,
    bool primary,
    ScrollPhysics physics,
    bool shrinkWrap = false,
    EdgeInsetsGeometry padding,
    @required IndexedWidgetBuilder itemBuilder,
    @required IndexedWidgetBuilder separatorBuilder,
    @required int itemCount,
    bool addAutomaticKeepAlives = true,
    bool addRepaintBoundaries = true,
    bool addSemanticIndexes = true,
    double cacheExtent,
  }) : assert(itemBuilder != null),
       assert(separatorBuilder != null),
       assert(itemCount != null && itemCount >= 0),
       itemExtent = null,
       childrenDelegate = SliverChildBuilderDelegate(
         (BuildContext context, int index) {
           final int itemIndex = index ~/ 2;
           Widget widget;
           if (index.isEven) {
             widget = itemBuilder(context, itemIndex);
           } else {
             widget = separatorBuilder(context, itemIndex);
             assert(() {
               if (widget == null) {
                 throw FlutterError('separatorBuilder cannot return null.');
               }
               return true;
             }());
           }
           return widget;
         },
         childCount: _computeSemanticChildCount(itemCount),
         addAutomaticKeepAlives: addAutomaticKeepAlives,
         addRepaintBoundaries: addRepaintBoundaries,
         addSemanticIndexes: addSemanticIndexes,
         semanticIndexCallback: (Widget _, int index) {
           return index.isEven ? index ~/ 2 : null;
         },
       ),
       super(
         key: key,
         scrollDirection: scrollDirection,
         reverse: reverse,
         controller: controller,
         primary: primary,
         physics: physics,
         shrinkWrap: shrinkWrap,
         padding: padding,
         cacheExtent: cacheExtent,
         semanticChildCount: _computeSemanticChildCount(itemCount),
       );

方式四
构造需要SliverChildDelegate提供自定义子项的其他方面的能力。例如,SliverChildDelegate可以控制用于估计实际上不可见的子项大小的算法。
上面几种模式基本可以满足业务需求,如果你还想做一些其它设置(如列表的最大滚动范围)或获取滑动时每次布局的子Item范围,可以尝试custom模式

 const ListView.custom({
    Key key,
    Axis scrollDirection = Axis.vertical,
    bool reverse = false,
    ScrollController controller,
    bool primary,
    ScrollPhysics physics,
    bool shrinkWrap = false,
    EdgeInsetsGeometry padding,
    this.itemExtent,
    @required this.childrenDelegate,
    double cacheExtent,
    int semanticChildCount,
  }) : assert(childrenDelegate != null),
       super(
         key: key,
         scrollDirection: scrollDirection,
         reverse: reverse,
         controller: controller,
         primary: primary,
         physics: physics,
         shrinkWrap: shrinkWrap,
         padding: padding,
         cacheExtent: cacheExtent,
         semanticChildCount: semanticChildCount,
       );

常用属性

属性名 功能 值所属类型
children 列表元素 List
scrollDirection Axis.horizontal 水平列表Axis.vertical 垂直列表 Axis
padding 内边距 EdgeInsetsGeometry
resolve 组件反向排序 bool
基本使用
/*
 *listView 的基本使用方法 
 */
class MyListView extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(
      child: ListView(
        children: [
          ListTile(
            leading: Icon(Icons.phone),
            title: Text(
              "你好数据的交换机",
              style: TextStyle(fontSize: 28.0),
            ),
            subtitle: Text(
              "listview listview",
              style: TextStyle(fontSize: 18.0),
            ),
          ),
          ListTile(
            leading: Icon(Icons.phone),
            title: Text(
              "你好数据的交换机",
              style: TextStyle(fontSize: 28.0),
            ),
            subtitle: Text(
              "listview listview",
              style: TextStyle(fontSize: 18.0),
            ),
          ),
          ListTile(
            leading: Icon(Icons.phone),
            title: Text(
              "你好数据的交换机",
              style: TextStyle(fontSize: 28.0),
            ),
            subtitle: Text(
              "listview listview",
              style: TextStyle(fontSize: 18.0),
            ),
          ),
          ListTile(
            leading: Icon(Icons.phone),
            title: Text(
              "你好数据的交换机",
              style: TextStyle(fontSize: 28.0),
            ),
            subtitle: Text(
              "listview listview",
              style: TextStyle(fontSize: 18.0),
            ),
          ),
          ListTile(
            leading: Icon(Icons.phone),
            title: Text(
              "你好数据的交换机",
              style: TextStyle(fontSize: 28.0),
            ),
            subtitle: Text(
              "listview listview",
              style: TextStyle(fontSize: 18.0),
            ),
          ),ListTile(
            leading: Icon(Icons.phone),
            title: Text(
              "你好数据的交换机",
              style: TextStyle(fontSize: 28.0),
            ),
            subtitle: Text(
              "listview listview",
              style: TextStyle(fontSize: 18.0),
            ),
          ),
          ListTile(
            leading: Icon(Icons.phone),
            title: Text(
              "你好数据的交换机",
              style: TextStyle(fontSize: 28.0),
            ),
            subtitle: Text(
              "listview listview",
              style: TextStyle(fontSize: 18.0),
            ),
          )
        ],
      ),
    );
  }
}

ListView.separated带有下划线的ListView

/**
 * 带有下划线的listview
 */
class MyListView2 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ListView.separated(
      itemCount: 100,
      itemBuilder: (BuildContext context, int index) {
        if (index.isOdd) {
          return new Container(
            padding: new EdgeInsets.all(15.0),
            child: new Text(
              "builder 奇数 Item " + index.toString(),
              style:
                  new TextStyle(fontSize: 20.0, color: new Color(0xFFFF0000)),
            ),
          );
        } else {
          return new Container(
            padding: new EdgeInsets.all(15.0),
            child: new Text(
              "builder 偶数 Item " + index.toString(),
              style:
                  new TextStyle(fontSize: 20.0, color: new Color(0xFF0000FF)),
            ),
          );
        }
      },
      separatorBuilder: (BuildContext context, int index) {
        return new Divider(
          color: new Color(0xFF888888),
        );
      },
    );
  }
}

ListView.builder 的用法

@override
  Widget build(BuildContext context) {
    return ListView.builder(
      itemCount: 100, //多少数据
      itemBuilder: (BuildContext context, int index) {
        if (index.isOdd) {
          return new Container(
            padding: new EdgeInsets.all(15.0),
            child: new Text(
              "builder 奇数 Item " + index.toString(),
              style:
                  new TextStyle(fontSize: 20.0, color: new Color(0xFFFF0000)),
            ),
          );
        } else {
          return new Container(
            padding: new EdgeInsets.all(15.0),
            child: new Text(
              "builder 偶数 Item " + index.toString(),
              style:
                  new TextStyle(fontSize: 20.0, color: new Color(0xFF0000FF)),
            ),
          );
        }
      },
    );
  }
}

ListView.custom 的用法


class MyListView1 extends StatefulWidget {
  @override
  _MyListViewState createState() => _MyListViewState();
}

class _MyListViewState extends State {
  List items = ['1', '2', '3', '4', '5'];

  void _reverse() {
    setState(() {
      items = items.reversed.toList();
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        child: ListView.custom(
          childrenDelegate: SliverChildBuilderDelegate(
              (BuildContext context, int index) {
                return KeepAlive(
                  data: items[index],
                  key: ValueKey(items[index]),
                );
              },
              childCount: items.length,
              findChildIndexCallback: (Key key) {
                final ValueKey valueKey = key;
                final String data = valueKey.value;
                return items.indexOf(data);
              }),
        ),
      ),
      bottomNavigationBar: BottomAppBar(
        child: Row(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            FlatButton(
              onPressed: () => _reverse(),
              child: Text('Reverse items'),
            ),
          ],
        ),
      ),
    );
  }
}

网络请求

/*
 * 请求网络数据
 */

class MyListView3 extends StatelessWidget {
  List _getListData() {
    var tempList = listData.map((value) {
      return ListTile(
          title: Text(value["title"]),
          leading: Image.network(value["imageUrl"],fit: BoxFit.cover,));
      // return Image(
      //   image:  NetworkImage(value["imageUrl"]),
      //    width: 300.0,
      //   height: 200.0,
      //   fit: BoxFit.cover,
      // );

     
    });

    return tempList.toList();
  }

  @override
  Widget build(BuildContext context) {
    return ListView(children: this._getListData());
  }
}

你可能感兴趣的:(Flutter 基本组件ListlView)