Flutter ListView 用法詳解

ListView的4種構造方式

默認構造函數(傳入 List children)

ListView(
          children: <Widget>[
            ListTile(title: Text("普通ListView")),
            ListTile(
                title: Text("ListView.build"),
                onTap: () {
                  Navigator.pushNamed(context, '/listview_build');
                }),
          ],
        )
複製代碼

適用場景:已知有限個Item的狀況下android

builder

ListView.builder(
            itemBuilder: (context, index) => Text("Item $index"),
            itemCount: 100)
複製代碼

適用場景:長列表時採用builder模式,能提升性能。不是把全部子控件都構造出來,而是在控件viewport加上頭尾的cacheExtent這個範圍內的子Item纔會被構造。在構造時傳遞一個builder,按需加載是一個慣用模式,能提升加載性能。git

構造多種樣式的Item

abstract class ListItem {}

class HeadingItem implements ListItem {
  final String heading;

  HeadingItem(this.heading);
}

class MessageItem implements ListItem {
  final String sender;
  final String body;

  MessageItem(this.sender, this.body);
}

ListView.builder(
            itemBuilder: (context, index) {
              final item = items[index];

              if (item is HeadingItem) {
                return ListTile(
                  title: Text(
                    item.heading,
                    style: Theme.of(context).textTheme.headline,
                  ),
                );
              } else if (item is MessageItem) {
                return ListTile(
                  title: Text(item.sender),
                  subtitle: Text(item.body),
                );
              }
            },
            itemCount: items.length))
複製代碼

separated

ListView.separated(
            itemBuilder: (context, index) {
              return Text("Item $index");
            },
            separatorBuilder: (context, index) {
              return Container(
                color: Colors.grey,
                height: 3,
              );
            },
            itemCount: 100)
複製代碼

適用場景:列表中須要分割線時,能夠自定義複雜的分割線github

custom

須要自定義SliverChildDelegate,各方法含義以下:緩存

ListView.custom(childrenDelegate: CustomSliverChildDelegate())

class CustomSliverChildDelegate extends SliverChildDelegate {
  /// 根據index構造child
  @override
  Widget build(BuildContext context, int index) {
    // KeepAlive將把全部子控件加入到cache,已輸入的TextField文字不會因滾動消失
    // 僅用於演示
    return KeepAlive(
        keepAlive: true,
        child: TextField(decoration: InputDecoration(hintText: '請輸入')));
  }

  /// 決定提供新的childDelegate時是否須要從新build。在調用此方法前會作類型檢查,不一樣類型時纔會調用此方法,因此通常返回true。
  @override
  bool shouldRebuild(SliverChildDelegate oldDelegate) {
    return true;
  }

  /// 提升children的count,當沒法精確知道時返回null。
  /// 當 build 返回 null時,它也將須要返回一個非null值
  @override
  int get estimatedChildCount => 100;

  /// 預計最大可滑動高度,若是設置的太小會致使部分child不可見,設置報錯
  @override
  double estimateMaxScrollOffset(int firstIndex, int lastIndex,
      double leadingScrollOffset, double trailingScrollOffset) {
    return 2500;
  }

  /// 完成layout後的回調,能夠經過該方法獲已完成佈局的視圖樹包括哪些子控件
  @override
  void didFinishLayout(int firstIndex, int lastIndex) {
    print('didFinishLayout firstIndex=$firstIndex firstIndex=$lastIndex');
  }
}
複製代碼

適用場景:上面幾種模式基本能夠知足業務需求,若是你還想作一些其它設置(如列表的最大滾動範圍)或獲取滑動時每次佈局的子Item範圍,能夠嘗試custom模式bash

ListView屬性含義

ListView的屬性

  • itemExtent: 指定Item在滑動方向上的高度,用來提升滑動性能

繼承自父控件 BoxScrollView 的屬性

  • padding: 用來設置BoxScrollView中子控件與父控件的間距

繼承自 ScrollView 的屬性

  • ScrollDirection: 滾動方向
  • reverse:決定滾動方向是否與閱讀方向一致
  • scrollController:控制滾動的位置
  • primary:當內容不足以滾動時,是否支持滾動;對於iOS系統還有一個效果:當用戶點擊狀態欄時是否滑動到頂部。
  • ScrollPhysics:控制用戶滾動視圖的交互
    • AlwaysScrollableScrollPhysics:列表老是可滾動的。在iOS上會有回彈效果,在android上不會回彈。那麼問題來了,若是primary設置爲false(內容不足時不滾動),且 physics設置爲AlwaysScrollableScrollPhysics,列表是否能夠滑動?答案是能夠,感興趣的能夠試一下
    • PageScrollPhysics:通常是給PageView控件用的滑動效果。若是listview設置的話在滑動到末尾時會有個比較大的彈起和回彈
    • ClampingScrollPhysics:滾動時沒有回彈效果,同android系統的listview效果
    • NeverScrollableScrollPhysics:就算內容超過列表範圍也不會滑動
    • BouncingScrollPhysics:不論什麼平臺都會有回彈效果
    • FixedExtentScrollPhysics:不適用於ListView,緣由:須要指定scroller爲FixedExtentScrollController,這個scroller只能用於ListWheelScrollViews
  • shrinkWrap: scroll view在滑動方向上的高度是否由內容高度決定,false:則高度爲滑動方向上的最大容許高度;若是在滑動方向上沒有設置約束,則這個字段必須設置爲true,不然會報錯。
  • cacheExtent:可見區域的先後會有必定高度的空間去緩存子控件,當滑動時就能夠迅速呈現
  • semanticChildCount:有含義的子控件的數量,如ListView會用children的長度,ListView.separated會用children長度的一半

用於構造SliverChildListDelegate的屬性

  • addAutomaticKeepAlives:是否將子控件包裹在AutomaticKeepAlive控件內
  • addRepaintBoundaries:true:是否將子控件包裹在 RepaintBoundary 控件內。用於避免列表滾動時的重繪,若是子控件重繪開銷很小時,好比子控件就是個色塊或簡短的文字,把這個字段設置爲false性能會更好
  • addSemanticIndexes:是否把子控件包裝在IndexedSemantics裏,用來提供無障礙語義

最後

ListView最爲app最多見的控件之一,掌握它的用法很是重要。本文主要給Flutter萌新們介紹ListView的幾種構造方式和參數含義,視圖控件的學習應多動手寫寫demo,真實體會各個參數的效果。app

最後附上demo以供參考。ide

@akindone, 本文版權屬於再惠研發團隊,歡迎轉載,轉載請保留出處。函數

相關文章
相關標籤/搜索