一、介紹

之前我寫了一篇關於 Flutter ListView Widget 的各種花里胡哨的使用,基本上能夠滿足日常的 ListView 使用需求,文章地址:

不過可以發現的是,我們都是在直接使用 ListView() 構造函數,實際上除了直接使用 ListView(children: List<Widget>) 的方式之外,還有 ListView.builder 和 ListView.separated 兩個構造函數可以構造 ListView

二、ListView.builder() 渲染長列表數據

下面是 ListView.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.

直接使用 ListView(children: List<Widget>) 的優點是簡單邊界,直接生成一個 List<Widget> 的列表,然后賦值給 ListView 的 children 參數即可

缺點是整個 ListView 是沒有回收機制的,會一次性創建出所有的子項,構建完成整個 ListView。

這意味着一旦列表長度非常長,比如 無限滾動列表的場景中,列表長度非常長,直接創建 ListView 的所有子項可能會有內存問題,過高的內存會引起 Crash

如果你使用過 RN 或者是 Weex 它們都有 RecycleList 的概念。

本身 ListView 是繼承自 BoxScrollView 繼承自 ScrollView 實現的,而如果直接使用 ListView 的構造函數,傳遞給 SliverChildBuilderDelegate 的是 children,而如果使用 ListView.builder 傳遞給 SliverChildBuilderDelegate 這是 builder,這里不詳細展開。

ListView.builder 接受兩個參數:

  • itemCount: int
  • itemBuilder: @required IndexedWidgetBuilder itemBuilder,

1、ListView.builder 的參數 itemCount

itemCount 這個參數聲明了 list 的長度,這個值表明 ListView 中會存在多少個 item 子項

2、ListView.builder 的參數 itemBuilder

從 itemBuilder 的表面含以上也能夠知道它是用來構造每個子項組件的,它的類型是 IndexedWidgetBuilder,其實是一個方法,接受 context 和 index 兩個參數。

  • context:構造的上下文
  • index: 當前索引

比如我的 itemBuilder 方法如下:

其實非常簡單,從 list 中通過 list[index] 拿到當前渲染的數據,然后返回一個 Widget 即可

  // item build 方法 Widget _buildListItem(BuildContext context, int index) { Map newsItem = newsList.news[index]; return ListItem( title: newsItem['title'], subTitle: newsItem['time'], cover: newsItem['imgurl']); }

3、完整的 ListView.builder 渲染

省略了 ListItem 的代碼,完整代碼可以在文章最后找到

class HomeContent extends StatelessWidget { // item build 方法 Widget _buildListItem(BuildContext context, int index) { Map newsItem = newsList.news[index]; return ListItem( title: newsItem['title'], subTitle: newsItem['time'], cover: newsItem['imgurl']); } 

最終的效果:

4.gif

三、ListView.separated 帶分隔符的列表

上面的列表中也可以發現,我們的列表是沒有分隔符的,雖然我們可以在每個 ListTile 中增加手動增加一個分隔符,但是 Flutter 的 ListView 已經給我們提供了便捷的方法。

ListView.separated 與 ListView.builder 的唯一不同就是多了個 separatorBuilder,類型也是 IndexedWidgetBuilder,其實也就是通過接受 BuildContext context, int index 兩個參數,再返回一個 Widget 

其他的和 ListView.builder 一樣使用

比如下面我的代碼:

省略了 this._buildListItem 的代碼,和上面一樣,完整代碼在文章最后

  // 能夠生成下划線的列表 

上面代碼中 我通過 index 控制了偶數藍色分割線,奇數是紅色分割線,最終效果:

60753-vie4zaz7ka.png

當然,separatorBuilder 不一定只能返回 Divider,只要是 Widget 就可以,比如我通過一個 Icon 作為分隔符:

      separatorBuilder: (BuildContext context, int index) { return index % 2 == 0 ? Icon(Icons.arrow_drop_down) : Icon(Icons.arrow_downward); },

75029-mx9st4h3mkh.png

四、完整代碼:

ListView.builder() 代碼:

ListView.separated() 代碼: