Flutter ListView的簡介

Table of Contents

Table of Contents

ListView是在Flutter中常見的具有滾軸的Widget。在做大量資料顯示時,例如像是圖片,文章,文字列表時,通常都會使用ListView來大量重複的相似的介面。你可以做直向滾動的ListView,也可以做橫向滾動的ListView,這些都是根據設計者的需求來決定。

這裡先介紹簡單的ListView的使用方法。

ListView

先從下面ListView的構造函數來看看,可以對ListView做哪些設定。

ListView({
    Key key, 
    Axis scrollDirection: Axis.vertical, 
    bool reverse: false, 
    ScrollController controller, 
    bool primary, 
    ScrollPhysics physics, 
    bool shrinkWrap: false, 
    EdgeInsetsGeometry padding, 
    double itemExtent, 
    bool addAutomaticKeepAlives: true, 
    bool addRepaintBoundaries: true, 
    bool addSemanticIndexes: true, 
    double cacheExtent, 
    List<Widget> children: const [], 
    int semanticChildCount, 
    DragStartBehavior dragStartBehavior: DragStartBehavior.start 
}) 

預設上,ListView是垂直方向的滾動列表。可以透過 scrollDirection 來做設定。 列表上的元素則是由 children 來做控制。一般來說,都是設定一組相似的UI List。

以下一個簡單的例子來顯示一個垂直滾動的列表。

ListView(
  children: <Widget>[
    Container(
      height: 50,
      color: Colors.amber[600],
      child: const Center(child: Text('Entry A')),
    ),
    Container(
      height: 50,
      color: Colors.amber[500],
      child: const Center(child: Text('Entry B')),
    ),
    Container(
      height: 50,
      color: Colors.amber[100],
      child: const Center(child: Text('Entry C')),
    ),
  ],
)

ListView.builder

除了像上面例子那樣直接用ListView之外,也可以用 ListView.builder 來製作列表。 先看看構造函數。

ListView.builder({
  Key key,
  Axis scrollDirection: Axis.vertical,
  bool reverse: false,
  ScrollController controller,
  bool primary, ScrollPhysics physics,
  bool shrinkWrap: false,
  EdgeInsetsGeometry padding,
  double itemExtent,
  @required IndexedWidgetBuilder itemBuilder,
  int itemCount,
  bool addAutomaticKeepAlives: true,
  bool addRepaintBoundaries: true,
  bool addSemanticIndexes: true,
  double cacheExtent, 
  int semanticChildCount,
  DragStartBehavior dragStartBehavior: DragStartBehavior.start
}) 

從上發現@required IndexedWidgetBuilder itemBuilder這個屬性,故得知使用ListView.builder時必須設定 itemBuilder

下面給了一個簡單的例子。

ListView.builder(
  itemBuilder: (BuildContext context, int index) {
    return Text(index.toString());
  }),

可以想像一下,當有一筆要顯示的數據時,使用ListView.builder的方式,只要在itemBuilder裡定義返回一個列表的項目UI後,它會按照定義去自動重複生成剩下的項目UI。

當然,也可以用ListView加上自製的重複生成UI的處理也可以做得到,而ListView.builder的方法中已經包含了重複生成UI的處理了,使用起來較為方便一點。

另外,根據官方網站上的描述,當製作大量的資料的列表時,推薦使用這個方法,因為他會在項目要顯示在螢幕時去呼叫builder,而非事先做好大量的項目,這樣可以節省負擔更加有效率。

This constructor is appropriate for list views with a large (or infinite) number of children because the builder is called only for those children that are actually visible.

稍微注意一下,上面的例子會產生一個無限項目的列表,也就是可以一直向下滾動列表,可以設定 itemCount的值來決定列表內項目的最大數目。


ListView.separated

某些場合,會需要各個項目之間能有個分隔的效果,像是一條分隔線。這個時候可以考慮使用 ListView.separated

照樣先來看一下構造函數。

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 }) 

與ListView.builder相比較一下,可以發現使用這個方法時,不只itemBuilder要定義,itemCount也成了必須指定的屬性,另外還要用 separatorBuilder 設定分隔UI。

以下給出一個簡單的例子。

ListView.separated(
  itemCount: entries.length,
  itemBuilder: (BuildContext context, int index) {
    return Container(
      height: 50,
      color: Colors.amber[colorCodes[index]],
      child: Center(child: Text('Entry ${entries[index]}')),
    );
  },
  separatorBuilder: (BuildContext context, int index) => const Divider(),
);

感想

ListView是個不可或缺的UI。這次簡單地了解了垂直列表的作法,下次想嘗試看看橫向列表的製作方式。如此才能因應不同場合製作出合適的列表UI。


參考