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)聽器的設置,在State中進行監(jiān)聽器的初始化。
//初始化滾動監(jiān)聽器,加載更多使用 ? ScrollController _controller = new ScrollController();
在構(gòu)造器中設置監(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();
? ? //設置當前導航欄的標題
? ? 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)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關文章
解決Android studio Error:(30, 31) 錯誤: 程序包 不存在的問題
這篇文章主要介紹了解決Android studio Error:(30, 31) 錯誤: 程序包 不存在的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-03-03
Android項目實戰(zhàn)教程之高仿網(wǎng)易云音樂啟動頁實例代碼
這篇文章主要給大家介紹了關于Android項目實戰(zhàn)教程之高仿網(wǎng)易云音樂啟動頁的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2018-09-09
Android 點擊ImageButton時有“按下”的效果的實現(xiàn)
這篇文章主要介紹了 Android 點擊ImageButton時有“按下”的效果的實現(xiàn)的相關資料,需要的朋友可以參考下2017-03-03
Android常用控件ImageSwitcher使用方法詳解
這篇文章主要為大家詳細介紹了Android常用控件ImageSwitcher的使用方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-08-08
Android開發(fā)Intent跳轉(zhuǎn)傳遞list集合實現(xiàn)示例
這篇文章主要為大家介紹了Android開發(fā)Intent跳轉(zhuǎn)傳遞list集合實現(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-07-07
Android使用Kotlin和RxJava 2.×實現(xiàn)短信驗證碼倒計時效果
本篇文章主要介紹了Android使用Kotlin和RxJava 2.×實現(xiàn)短信驗證碼倒計時效果,非常具有實用價值,需要的朋友可以參考下2017-12-12

