Flutter實現(xiàn)下拉刷新和上拉加載更多
本文實例為大家分享了Flutter實現(xiàn)下拉刷新和上拉加載更多的具體代碼,供大家參考,具體內(nèi)容如下
效果
下拉刷新
如果實現(xiàn)下拉刷新,必須借助RefreshIndicator,在listview外面包裹一層RefreshIndicator,然后在RefreshIndicator里面實現(xiàn)onRefresh方法。
body: movieList.length == 0 ? ? ? ? ? ? new Center(child: new CircularProgressIndicator()) ? ? ? ? ? : new RefreshIndicator( ? ? ? ? ? ? ? color: const Color(0xFF4483f6), ? ? ? ? ? ? ? //下拉刷新 ? ? ? ? ? ? ? child: ListView.builder( ? ? ? ? ? ? ? ? itemCount: movieList.length + 1, ? ? ? ? ? ? ? ? itemBuilder: (context, index) { ? ? ? ? ? ? ? ? ? if (index == movieList.length) { ? ? ? ? ? ? ? ? ? ? return _buildProgressMoreIndicator(); ? ? ? ? ? ? ? ? ? } else { ? ? ? ? ? ? ? ? ? ? return renderRow(index, context); ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? }, ? ? ? ? ? ? ? ? controller: _controller, //指明控制器加載更多使用 ? ? ? ? ? ? ? ), ? ? ? ? ? ? ? onRefresh: _pullToRefresh, ? ? ? ? ? ? ),
onRefresh方法的實現(xiàn)_pullToRefresh,注意這里必須使用async 不然報錯
?/** ? ?* 下拉刷新,必須異步async不然會報錯 ? ?*/ ? Future _pullToRefresh() async { ? ? currentPage = 0; ? ? movieList.clear(); ? ? loadMoreData(); ? ? return null; ? }
異步加載數(shù)據(jù),注意:在Flutter中刷新數(shù)據(jù)使用的是setState,不然無效,數(shù)據(jù)不會刷新;數(shù)據(jù)的獲取需要使用[]取值,不能使用對象“ . ”的取值方法!
//加載列表數(shù)據(jù) loadMoreData() async { ? ? this.currentPage++; ? ? var start = (currentPage - 1) * pageSize; ? ? var url = ? ? ? ? "https://api.douban.com/v2/movie/$movieType?start=$start&count=$pageSize"; ? ? Dio dio = new Dio(); ? ? Response response = await dio.get(url); ? ? setState(() { ? ? ? movieList.addAll(response.data["subjects"]); ? ? ? totalSize = response.data["total"]; ? ? }); ? }
上拉加載更多
加載更多需要對ListView進行監(jiān)聽,所以需要進行監(jiān)聽器的設(shè)置,在State中進行監(jiān)聽器的初始化。
//初始化滾動監(jiān)聽器,加載更多使用 ? ScrollController _controller = new ScrollController();
在構(gòu)造器中設(shè)置監(jiān)聽
?//固定寫法,初始化滾動監(jiān)聽器,加載更多使用 ? ? _controller.addListener(() { ? ? ? var maxScroll = _controller.position.maxScrollExtent; ? ? ? var pixel = _controller.position.pixels; ? ? ? if (maxScroll == pixel && movieList.length < totalSize) { ? ? ? ? setState(() { ? ? ? ? ? loadMoreText = "正在加載中..."; ? ? ? ? ? loadMoreTextStyle = ? ? ? ? ? ? ? new TextStyle(color: const Color(0xFF4483f6), fontSize: 14.0); ? ? ? ? }); ? ? ? ? loadMoreData(); ? ? ? } else { ? ? ? ? setState(() { ? ? ? ? ? loadMoreText = "沒有更多數(shù)據(jù)"; ? ? ? ? ? loadMoreTextStyle = ? ? ? ? ? ? ? new TextStyle(color: const Color(0xFF999999), fontSize: 14.0); ? ? ? ? }); ? ? ? } ? ? });
在listView中添加監(jiān)聽controller方法
自此,F(xiàn)lutter如何實現(xiàn)下拉刷新和上拉加載更多完成…
整個列表頁面代碼參考如下:
import 'package:flutter/material.dart'; import 'package:dio/dio.dart'; import 'package:douban/pages/movie/movieDetail.dart'; class MovieList extends StatefulWidget { ? String movieType; ? //構(gòu)造器傳遞數(shù)據(jù)(并且接收上個頁面?zhèn)鬟f的數(shù)據(jù)) ? MovieList({Key key, this.movieType}) : super(key: key); ? @override ? State<StatefulWidget> createState() { ? ? // TODO: implement createState ? ? return new MovieListState(movieType: this.movieType); ? } } class MovieListState extends State<MovieList> { ? String movieType; ? String typeName; ? List movieList = new List(); ? int currentPage = 0; //第一頁 ? int pageSize = 10; //頁容量 ? int totalSize = 0; //總條數(shù) ? String loadMoreText = "沒有更多數(shù)據(jù)"; ? TextStyle loadMoreTextStyle = ? ? ? new TextStyle(color: const Color(0xFF999999), fontSize: 14.0); ? TextStyle titleStyle = ? ? ? new TextStyle(color: const Color(0xFF757575), fontSize: 14.0); ? //初始化滾動監(jiān)聽器,加載更多使用 ? ScrollController _controller = new ScrollController(); ? /** ? ?* 構(gòu)造器接收(MovieList)數(shù)據(jù) ? ?*/ ? MovieListState({Key key, this.movieType}) { ? ? //固定寫法,初始化滾動監(jiān)聽器,加載更多使用 ? ? _controller.addListener(() { ? ? ? var maxScroll = _controller.position.maxScrollExtent; ? ? ? var pixel = _controller.position.pixels; ? ? ? if (maxScroll == pixel && movieList.length < totalSize) { ? ? ? ? setState(() { ? ? ? ? ? loadMoreText = "正在加載中..."; ? ? ? ? ? loadMoreTextStyle = ? ? ? ? ? ? ? new TextStyle(color: const Color(0xFF4483f6), fontSize: 14.0); ? ? ? ? }); ? ? ? ? loadMoreData(); ? ? ? } else { ? ? ? ? setState(() { ? ? ? ? ? loadMoreText = "沒有更多數(shù)據(jù)"; ? ? ? ? ? loadMoreTextStyle = ? ? ? ? ? ? ? new TextStyle(color: const Color(0xFF999999), fontSize: 14.0); ? ? ? ? }); ? ? ? } ? ? }); ? } ? //加載列表數(shù)據(jù) ? loadMoreData() async { ? ? this.currentPage++; ? ? var start = (currentPage - 1) * pageSize; ? ? var url = ? ? ? ? "https://api.douban.com/v2/movie/$movieType?start=$start&count=$pageSize"; ? ? Dio dio = new Dio(); ? ? Response response = await dio.get(url); ? ? setState(() { ? ? ? movieList.addAll(response.data["subjects"]); ? ? ? totalSize = response.data["total"]; ? ? }); ? } ? @override ? void initState() { ? ? super.initState(); ? ? //設(shè)置當(dāng)前導(dǎo)航欄的標題 ? ? switch (movieType) { ? ? ? case "in_theaters": ? ? ? ? typeName = "正在熱映"; ? ? ? ? break; ? ? ? case "coming_soon": ? ? ? ? typeName = "即將上映"; ? ? ? ? break; ? ? ? case "top250": ? ? ? ? typeName = "Top250"; ? ? ? ? break; ? ? } ? ? //加載第一頁數(shù)據(jù) ? ? loadMoreData(); ? } ? /** ? ?* 下拉刷新,必須異步async不然會報錯 ? ?*/ ? Future _pullToRefresh() async { ? ? currentPage = 0; ? ? movieList.clear(); ? ? loadMoreData(); ? ? return null; ? } ? @override ? Widget build(BuildContext context) { ? ? // TODO: implement build ? ? return new Scaffold( ? ? ? backgroundColor: Colors.white, ? ? ? appBar: new AppBar( ? ? ? ? leading: new IconButton( ? ? ? ? ? icon: const Icon(Icons.arrow_back), ? ? ? ? ? onPressed:null , ? ? ? ? ), ? ? ? ? title: new Text(typeName != null ? typeName : "正在加載中...", ? ? ? ? ? ? style: new TextStyle(color: Colors.black)), ? ? ? ? backgroundColor: Colors.white, ? ? ? ), ? ? ? body: movieList.length == 0 ? ? ? ? ? ? new Center(child: new CircularProgressIndicator()) ? ? ? ? ? : new RefreshIndicator( ? ? ? ? ? ? ? color: const Color(0xFF4483f6), ? ? ? ? ? ? ? //下拉刷新 ? ? ? ? ? ? ? child: ListView.builder( ? ? ? ? ? ? ? ? itemCount: movieList.length + 1, ? ? ? ? ? ? ? ? itemBuilder: (context, index) { ? ? ? ? ? ? ? ? ? if (index == movieList.length) { ? ? ? ? ? ? ? ? ? ? return _buildProgressMoreIndicator(); ? ? ? ? ? ? ? ? ? } else { ? ? ? ? ? ? ? ? ? ? return renderRow(index, context); ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? }, ? ? ? ? ? ? ? ? controller: _controller, //指明控制器加載更多使用 ? ? ? ? ? ? ? ), ? ? ? ? ? ? ? onRefresh: _pullToRefresh, ? ? ? ? ? ? ), ? ? ); ? } ? /** ? ?* 加載更多進度條 ? ?*/ ? Widget _buildProgressMoreIndicator() { ? ? return new Padding( ? ? ? padding: const EdgeInsets.all(15.0), ? ? ? child: new Center( ? ? ? ? child: new Text(loadMoreText, style: loadMoreTextStyle), ? ? ? ), ? ? ); ? } ? /** ? ?* 列表的ltem ? ?*/ ? renderRow(index, context) { ? ? var movie = movieList[index]; ? ? var id = movie["id"]; ? ? var title = movie["title"]; ? ? var type = movie["genres"].join("、"); ? ? var year = movie["year"]; ? ? var score = movie["rating"]["average"]; ? ? return new Container( ? ? ? ? height: 200, ? ? ? ? color: Colors.white, ? ? ? ? child: new InkWell( ? ? ? ? ? onTap: () { ? ? ? ? ? ? Navigator.of(context).push(new MaterialPageRoute( ? ? ? ? ? ? ? ? builder: (ctx) => new MovieDetail(movieId: id))); ? ? ? ? ? }, ? ? ? ? ? child: new Column( ? ? ? ? ? ? children: <Widget>[ ? ? ? ? ? ? ? new Container( ? ? ? ? ? ? ? ? height: 199, ? ? ? ? ? ? ? ? // color: Colors.blue, ? ? ? ? ? ? ? ? child: new Row( ? ? ? ? ? ? ? ? ? children: <Widget>[ ? ? ? ? ? ? ? ? ? ? new Container( ? ? ? ? ? ? ? ? ? ? ? width: 120.0, ? ? ? ? ? ? ? ? ? ? ? height: 180.0, ? ? ? ? ? ? ? ? ? ? ? margin: const EdgeInsets.all(10.0), ? ? ? ? ? ? ? ? ? ? ? child: Image.network(movie["images"]["small"]), ? ? ? ? ? ? ? ? ? ? ), ? ? ? ? ? ? ? ? ? ? Expanded( ? ? ? ? ? ? ? ? ? ? ? child: new Container( ? ? ? ? ? ? ? ? ? ? ? ? height: 180.0, ? ? ? ? ? ? ? ? ? ? ? ? margin: const EdgeInsets.all(12.0), ? ? ? ? ? ? ? ? ? ? ? ? child: new Column( ? ? ? ? ? ? ? ? ? ? ? ? ? mainAxisAlignment: MainAxisAlignment.spaceBetween, ? ? ? ? ? ? ? ? ? ? ? ? ? crossAxisAlignment: CrossAxisAlignment.start, ? ? ? ? ? ? ? ? ? ? ? ? ? children: <Widget>[ ? ? ? ? ? ? ? ? ? ? ? ? ? ? new Text( ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "電影名稱:$title", ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? style: titleStyle, ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? overflow: TextOverflow.ellipsis, ? ? ? ? ? ? ? ? ? ? ? ? ? ? ), ? ? ? ? ? ? ? ? ? ? ? ? ? ? new Text( ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "電影類型:$type", ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? style: titleStyle, ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? overflow: TextOverflow.ellipsis, ? ? ? ? ? ? ? ? ? ? ? ? ? ? ), ? ? ? ? ? ? ? ? ? ? ? ? ? ? new Text( ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "上映年份:$year", ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? style: titleStyle, ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? overflow: TextOverflow.ellipsis, ? ? ? ? ? ? ? ? ? ? ? ? ? ? ), ? ? ? ? ? ? ? ? ? ? ? ? ? ? new Text( ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "豆瓣評分:$score", ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? style: titleStyle, ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? overflow: TextOverflow.ellipsis, ? ? ? ? ? ? ? ? ? ? ? ? ? ? ) ? ? ? ? ? ? ? ? ? ? ? ? ? ], ? ? ? ? ? ? ? ? ? ? ? ? ), ? ? ? ? ? ? ? ? ? ? ? ), ? ? ? ? ? ? ? ? ? ? ), ? ? ? ? ? ? ? ? ? ], ? ? ? ? ? ? ? ? ), ? ? ? ? ? ? ? ), ? ? ? ? ? ? ? //分割線 ? ? ? ? ? ? ? new Divider(height: 1) ? ? ? ? ? ? ], ? ? ? ? ? ), ? ? ? ? )); ? } }
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
解決Android studio Error:(30, 31) 錯誤: 程序包 不存在的問題
這篇文章主要介紹了解決Android studio Error:(30, 31) 錯誤: 程序包 不存在的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-03-03Android項目實戰(zhàn)教程之高仿網(wǎng)易云音樂啟動頁實例代碼
這篇文章主要給大家介紹了關(guān)于Android項目實戰(zhàn)教程之高仿網(wǎng)易云音樂啟動頁的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2018-09-09Android 點擊ImageButton時有“按下”的效果的實現(xiàn)
這篇文章主要介紹了 Android 點擊ImageButton時有“按下”的效果的實現(xiàn)的相關(guān)資料,需要的朋友可以參考下2017-03-03Android常用控件ImageSwitcher使用方法詳解
這篇文章主要為大家詳細介紹了Android常用控件ImageSwitcher的使用方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-08-08Android開發(fā)Intent跳轉(zhuǎn)傳遞list集合實現(xiàn)示例
這篇文章主要為大家介紹了Android開發(fā)Intent跳轉(zhuǎn)傳遞list集合實現(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-07-07Android使用Kotlin和RxJava 2.×實現(xiàn)短信驗證碼倒計時效果
本篇文章主要介紹了Android使用Kotlin和RxJava 2.×實現(xiàn)短信驗證碼倒計時效果,非常具有實用價值,需要的朋友可以參考下2017-12-12