Flutter 实例 - 加载更多的ListView
Dart4Flutter - 01 – 變量、類型和函數
Dart4Flutter – 02 –控制流 和異常
Dart4Flutter – 03 – 類和泛型
Dart4Flutter – 04 – 異步和庫
Dart4Flutter - 拾遺01 - flutter-dart環境搭建
Dart4Flutter - 不可變性
Flutter入門 - 狀態管理
Flutter 入門實例1
Flutter 入門 - Container 屬性詳解
Flutter 入門-本地訪問-MethodChannel
Flutter 實例 - 加載更多的ListView
Flutter 實例 - 從本地到Flutter通信 - Event Channels
本教程完成一個有加載更多的ListView,最終效果如下圖所示:
開始
首先我們只在列表中展示10個整數。
class MyHomePage extends StatefulWidget {_MyHomePageState createState() => _MyHomePageState(); }class _MyHomePageState extends State<MyHomePage> {List<int> items = List.generate(10, (i) => i); // 產生數據void initState() {super.initState();}void dispose() {super.dispose();}Widget build(BuildContext context) {return new Scaffold(appBar: AppBar(title: Text("Infinite ListView"),),body: ListView.builder(itemCount: items.length,itemBuilder: (context, index) {return ListTile(title: new Text("Number $index"));},),);} } 復制代碼動態添加數據
首先我們模擬一個http請求,假設我們通過傳遞from和to參數,然后返回他們之間的數。我們將添加延遲時間,這樣看起來更像是網絡加載。具體代碼如下所示:
/// from - 包括, to - 不包括 /// 通過這個模擬http請求 Future<List<int>> fakeRequest(int from, int to) async { // 如果對Future不熟悉,可以參考 https://juejin.im/post/5b2c67a351882574a756f2ebreturn Future.delayed(Duration(seconds: 2), () {return List.generate(to - from, (i) => i + from);}); } 復制代碼當用戶將列表滾動到最底,我們將會調用上面的方法。為了監聽列表是否已經滾動到最底,最簡單的方式就是給列表添加一個ScrollController,當列表滾動的時候,就會發出一個請求。但是防止頻繁的發送http請求,我們需要添加一個變量isPerformingRequest,表示是否有請求正在進行。只有當isPerformingRequest為false時,才能開始一個新的請求。
class _MyHomePageState extends State<MyHomePage> {List<int> items = List.generate(10, (i) => i);ScrollController _scrollController = new ScrollController();bool isPerformingRequest = false; // 是否有請求正在進行void initState() {super.initState();_scrollController.addListener(() {if (_scrollController.position.pixels == _scrollController.position.maxScrollExtent) {_getMoreData();}});}void dispose() {_scrollController.dispose();super.dispose();}_getMoreData() async {if (!isPerformingRequest) { // 判斷是否有請求正在執行setState(() => isPerformingRequest = true);List<int> newEntries = await fakeRequest(items.length, items.length + 10);setState(() {items.addAll(newEntries);isPerformingRequest = false;// 下一個請求可以開始了});}}Widget build(BuildContext context) {return new Scaffold(appBar: AppBar(title: Text("Infinite ListView"),),body: ListView.builder(itemCount: items.length,itemBuilder: (context, index) {return ListTile(title: new Text("Number $index"));},controller: _scrollController,),);} } 復制代碼如果你現在運行代碼,你可以看數據可以動態的加載,但是這個距離我們最終想要的效果還有差距。我們需要添加一些提示,告知用戶數據正在加載中。
進度提示
相關的組件是CircularProgressIndicator,他被Center、Opacity、Padding所包裹。我們將用Opacity組件控制CircularProgressIndicator的顯示,當請求正在進行中時顯示。整個組件的代碼如下所示:
Widget _buildProgressIndicator() {return new Padding(padding: const EdgeInsets.all(8.0),child: new Center(child: new Opacity(opacity: isPerformingRequest ? 1.0 : 0.0,child: new CircularProgressIndicator(),),),); } 復制代碼最后一件事是將這個組件添加到我們的ListView上:
Widget build(BuildContext context) {return new Scaffold(appBar: AppBar(title: Text("Infinite ListView"),),body: ListView.builder(itemCount: items.length + 1,itemBuilder: (context, index) {if (index == items.length) {return _buildProgressIndicator();} else {return ListTile(title: new Text("Number $index"));}},controller: _scrollController,),); } 復制代碼最終效果如下:
處理空數據情況
下面是附加內容,處理當請求返回的數據為空時的晴空。我們通過ScrollController給ListView一些動畫。
_getMoreData() async {if (!isPerformingRequest) {setState(() => isPerformingRequest = true);List<int> newEntries = await fakeRequest(items.length, items.length); //returns empty listif (newEntries.isEmpty) {double edge = 50.0;double offsetFromBottom = _scrollController.position.maxScrollExtent - _scrollController.position.pixels;if (offsetFromBottom < edge) {_scrollController.animateTo(_scrollController.offset - (edge -offsetFromBottom),duration: new Duration(milliseconds: 500),curve: Curves.easeOut);}}setState(() {items.addAll(newEntries);isPerformingRequest = false;});} } 復制代碼 下面是完整的代碼: import 'dart:async';import 'package:flutter/material.dart';void main() => runApp(new MyApp());class MyApp extends StatelessWidget {Widget build(BuildContext context) {return new MaterialApp(theme: new ThemeData(primarySwatch: Colors.blue),home: new MyHomePage(),);} }class MyHomePage extends StatefulWidget {_MyHomePageState createState() => _MyHomePageState(); }class _MyHomePageState extends State<MyHomePage> {List<int> items = List.generate(10, (i) => i);ScrollController _scrollController = new ScrollController();bool isPerformingRequest = false;void initState() {super.initState();_scrollController.addListener(() {if (_scrollController.position.pixels ==_scrollController.position.maxScrollExtent) {_getMoreData();}});}void dispose() {_scrollController.dispose();super.dispose();}_getMoreData() async {if (!isPerformingRequest) {setState(() => isPerformingRequest = true);List<int> newEntries = await fakeRequest(items.length, items.length + 10); //returns empty listif (newEntries.isEmpty) {double edge = 50.0;double offsetFromBottom = _scrollController.position.maxScrollExtent -_scrollController.position.pixels;if (offsetFromBottom < edge) {_scrollController.animateTo(_scrollController.offset - (edge - offsetFromBottom),duration: new Duration(milliseconds: 500),curve: Curves.easeOut);}}setState(() {items.addAll(newEntries);isPerformingRequest = false;});}}Widget _buildProgressIndicator() {return new Padding(padding: const EdgeInsets.all(8.0),child: new Center(child: new Opacity(opacity: isPerformingRequest ? 1.0 : 0.0,child: new CircularProgressIndicator(),),),);}Widget build(BuildContext context) {return new Scaffold(appBar: AppBar(title: Text("Infinite ListView"),),body: ListView.builder(itemCount: items.length + 1,itemBuilder: (context, index) {if (index == items.length) {return _buildProgressIndicator();} else {return ListTile(title: new Text("Number $index"));}},controller: _scrollController,),);} }/// from - inclusive, to - exclusive Future<List<int>> fakeRequest(int from, int to) async {return Future.delayed(Duration(seconds: 2), () {return List.generate(to - from, (i) => i + from);}); } 復制代碼有任何問題,歡迎大家提問
參考
- marcinszalek.pl/flutter/inf…
總結
以上是生活随笔為你收集整理的Flutter 实例 - 加载更多的ListView的全部內容,希望文章能夠幫你解決所遇到的問題。