一、介紹
之前我寫了一篇關於 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']); }
最終的效果:
三、ListView.separated 帶分隔符的列表
上面的列表中也可以發現,我們的列表是沒有分隔符的,雖然我們可以在每個 ListTile
中增加手動增加一個分隔符,但是 Flutter 的 ListView 已經給我們提供了便捷的方法。
ListView.separated
與 ListView.builder
的唯一不同就是多了個 separatorBuilder
,類型也是 IndexedWidgetBuilder
,其實也就是通過接受 BuildContext context, int index
兩個參數,再返回一個 Widget
其他的和 ListView.builder
一樣使用
比如下面我的代碼:
省略了
this._buildListItem
的代碼,和上面一樣,完整代碼在文章最后
// 能夠生成下划線的列表
上面代碼中 我通過 index 控制了偶數藍色分割線,奇數是紅色分割線,最終效果:
當然,separatorBuilder
不一定只能返回 Divider
,只要是 Widget 就可以,比如我通過一個 Icon 作為分隔符:
separatorBuilder: (BuildContext context, int index) { return index % 2 == 0 ? Icon(Icons.arrow_drop_down) : Icon(Icons.arrow_downward); },
四、完整代碼:
ListView.builder() 代碼:
ListView.separated() 代碼: