Flutter 列表控件ListView

Flutter ListView

列表佈局在手機上是最最常用的控件了。
Android上的RecycleView尤其的強大。

Flutter中也給我們提供了ListView,不過就目前的體驗來看,性能跟原生的ListView或RecycleView比還是有一點差距的。滑動起來還是略卡。

下面我們來看一下ListView的相關知識

繼承關係
在這裏插入圖片描述

可以看到,ListView和GridView都繼承自BoxScrollView,因此,他們的屬性差不多,用法也相似。

構造方法

  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<Widget> children = const <Widget>[],
    int semanticChildCount,
    DragStartBehavior dragStartBehavior = DragStartBehavior.down,
  })

常用屬性

屬性 值類型 說明
scrollDirection Axis 設置滾動的方向,horizontal(水平)或vertical(垂直)
reverse bool 是否翻轉
itemExtent double 滾動方向子控件的長度,垂直方向即爲高度,水平方向即爲寬度
controller ScrollController 用來控制滾動位置及監聽滾動事件
shrinkWrap bool 是否根據子widget的總長度來設置ListView的長度
padding EdgeInsetsGeometry 間距
children List 子控件

常用屬性都比較簡單,沒啥好說的,我們來直接用一下

ListView(
      children: List.generate(30, (index) {
        return Container(
          alignment: Alignment.center,
          decoration: BoxDecoration(
            border: Border.all(color: Colors.red),
          ),
          child: Text("item${index}"),
        );
      }),
    );

效果圖:
在這裏插入圖片描述

這裏我們要注意一下itemExtent屬性
itemExtent
該屬性用來控制子控件在滾動方向上的長度,所以它跟scrollDirection是密切相關的。
例如:
當滾動方向爲垂直方向時,那麼itemExtent就是控制子控件的高度
當滾動方向爲水平方向時,那麼itemExtent就是控制子控件的寬度

示例:我們在垂直方向上設置一下itemExtent

ListView(
      scrollDirection: Axis.vertical,
      itemExtent: 60,
      children: List.generate(50, (index) {
        return Container(
          alignment: Alignment.center,
          decoration: BoxDecoration(
            border: Border.all(color: Colors.red),
          ),
          child: Text("item${index}"),
        );
      }),
    );

圖示如下:此時,itemExtent控制的是子控件的高度
在這裏插入圖片描述

我們更改一下滾動方向爲水平:

ListView(
      scrollDirection: Axis.horizontal,
      itemExtent: 60,
      children: List.generate(50, (index) {
        return Container(
          alignment: Alignment.center,
          decoration: BoxDecoration(
            border: Border.all(color: Colors.red),
          ),
          child: Text("item${index}"),
        );
      }),
    );

此時,itemExtent控制的就是子控件的寬度了
圖示:
在這裏插入圖片描述

Flutter ListView加載更多/異步加載(ListView.builder)

構造方法適合在數據較少且固定的情況下使用,我們在開發過程中一般數據都是從網絡獲取的,並且基本都有分頁的需求,此時,我們就需要動態的加載數據了。
GridView一樣,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,
    this.itemExtent,
    @required IndexedWidgetBuilder itemBuilder,
    int itemCount,
    bool addAutomaticKeepAlives = true,
    bool addRepaintBoundaries = true,
    bool addSemanticIndexes = true,
    double cacheExtent,
    int semanticChildCount,
    DragStartBehavior dragStartBehavior = DragStartBehavior.down,
  })

屬性跟構造方法中的屬性差不多,我們主要來看看itemCountitemBuilder

itemCount表示列表的數量,一般都是集合的長度
itemBuilder是列表項構造器,返回一個Widget

這裏我就直接用了

import 'package:flutter/material.dart';

/*
* 列表控件
*
* */
class ListViewWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ListView(
      scrollDirection: Axis.horizontal,
      itemExtent: 60,
      children: List.generate(50, (index) {
        return Container(
          alignment: Alignment.center,
          decoration: BoxDecoration(
            border: Border.all(color: Colors.red),
          ),
          child: Text("item${index}"),
        );
      }),
    );
  }
}

class ListViewBuilder extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return _ListViewBuilder();
  }
}

class _ListViewBuilder extends State<ListViewBuilder> {
  
  /*初始項爲50個*/
  List<int> indexs = List.generate(50, (index) {
    return index;
  });

  @override
  Widget build(BuildContext context) {
    return ListView.builder(
        itemCount: indexs.length,
        itemBuilder: (context, index) {
          
          /*加載到底部時且集合數量小於100的話,獲取更多數據*/
          if (index==indexs.length-1&&indexs.length < 100) {
            _getMoreData(index);
          }

          return Text("${index}");
        });
  }

  void _getMoreData(int index) {
    Future.delayed(Duration(milliseconds: 300)).then((e) {
      setState(() {
        /*往集合裏添加10條數據*/
        indexs.addAll(List.generate(10, (i) {
          return index + i;
        }));
      });
    });
  }
}

圖示:
初始值集合中只有50條數據,然後每次增加10條
在這裏插入圖片描述

Flutter ListView分割線(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,
  })

可以看到屬性中多了一個separatorBuilder

separatorBuilder即爲分割線構建器

下面我們給上面的列表加上灰色分割線:

import 'package:flutter/material.dart';

/*
* 列表控件
*
* */
class ListViewWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ListView(
      scrollDirection: Axis.horizontal,
      itemExtent: 60,
      children: List.generate(50, (index) {
        return Container(
          alignment: Alignment.center,
          decoration: BoxDecoration(
            border: Border.all(color: Colors.red),
          ),
          child: Text("item${index}"),
        );
      }),
    );
  }
}

class ListViewBuilder extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return _ListViewBuilder();
  }
}

class _ListViewBuilder extends State<ListViewBuilder> {
  /*初始項爲50個*/
  List<int> indexs = List.generate(50, (index) {
    return index;
  });

  @override
  Widget build(BuildContext context) {
    /*灰色分割線*/
    var divider = Divider(
      color: Colors.grey,
    );

    return ListView.separated(
        padding: EdgeInsets.all(10),
        itemCount: indexs.length,
        separatorBuilder: (context, index) {
          return divider;
        },
        itemBuilder: (context, index) {
          /*加載到底部時且集合數量小於100的話,獲取更多數據*/
          if (index == indexs.length - 1 && indexs.length < 100) {
            _getMoreData(index);
          }

          return Text("${index}");
        });
  }

  void _getMoreData(int index) {
    Future.delayed(Duration(milliseconds: 300)).then((e) {
      setState(() {
        /*往集合裏添加10條數據*/
        indexs.addAll(List.generate(10, (i) {
          return index + i;
        }));
      });
    });
  }
}

在這裏插入圖片描述

好了 Flutter ListView的基本用法大概就是這樣


如果你覺得本文對你有幫助,麻煩動動手指頂一下,算是對本文的一個認可。也可以關注我的 Flutter 博客專欄,我會不定期的更新,如果文中有什麼錯誤的地方,還望指正,轉載請註明轉自喻志強的博客 ,謝謝!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章