Flutter實(shí)現(xiàn)下拉刷新和上拉加載更多
本文實(shí)例為大家分享了Flutter實(shí)現(xiàn)下拉刷新和上拉加載更多的具體代碼,供大家參考,具體內(nèi)容如下
效果

下拉刷新
如果實(shí)現(xiàn)下拉刷新,必須借助RefreshIndicator,在listview外面包裹一層RefreshIndicator,然后在RefreshIndicator里面實(shí)現(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方法的實(shí)現(xiàn)_pullToRefresh,注意這里必須使用async 不然報(bào)錯(cuò)
?/**
? ?* 下拉刷新,必須異步async不然會(huì)報(bào)錯(cuò)
? ?*/
? Future _pullToRefresh() async {
? ? currentPage = 0;
? ? movieList.clear();
? ? loadMoreData();
? ? return null;
? }異步加載數(shù)據(jù),注意:在Flutter中刷新數(shù)據(jù)使用的是setState,不然無(wú)效,數(shù)據(jù)不會(huì)刷新;數(shù)據(jù)的獲取需要使用[]取值,不能使用對(duì)象“ . ”的取值方法!
//加載列表數(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"];
? ? });
? }上拉加載更多
加載更多需要對(duì)ListView進(jìn)行監(jiān)聽(tīng),所以需要進(jìn)行監(jiān)聽(tīng)器的設(shè)置,在State中進(jìn)行監(jiān)聽(tīng)器的初始化。
//初始化滾動(dòng)監(jiān)聽(tīng)器,加載更多使用 ? ScrollController _controller = new ScrollController();
在構(gòu)造器中設(shè)置監(jiān)聽(tīng)
?//固定寫(xiě)法,初始化滾動(dòng)監(jiān)聽(tīng)器,加載更多使用
? ? _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 = "沒(méi)有更多數(shù)據(jù)";
? ? ? ? ? loadMoreTextStyle =
? ? ? ? ? ? ? new TextStyle(color: const Color(0xFF999999), fontSize: 14.0);
? ? ? ? });
? ? ? }
? ? });在listView中添加監(jiān)聽(tīng)controller方法

自此,F(xiàn)lutter如何實(shí)現(xiàn)下拉刷新和上拉加載更多完成…
整個(gè)列表頁(yè)面代碼參考如下:
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ù)(并且接收上個(gè)頁(yè)面?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; //第一頁(yè)
? int pageSize = 10; //頁(yè)容量
? int totalSize = 0; //總條數(shù)
? String loadMoreText = "沒(méi)有更多數(shù)據(jù)";
? TextStyle loadMoreTextStyle =
? ? ? new TextStyle(color: const Color(0xFF999999), fontSize: 14.0);
? TextStyle titleStyle =
? ? ? new TextStyle(color: const Color(0xFF757575), fontSize: 14.0);
? //初始化滾動(dòng)監(jiān)聽(tīng)器,加載更多使用
? ScrollController _controller = new ScrollController();
? /**
? ?* 構(gòu)造器接收(MovieList)數(shù)據(jù)
? ?*/
? MovieListState({Key key, this.movieType}) {
? ? //固定寫(xiě)法,初始化滾動(dòng)監(jiān)聽(tīng)器,加載更多使用
? ? _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 = "沒(méi)有更多數(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)航欄的標(biāo)題
? ? switch (movieType) {
? ? ? case "in_theaters":
? ? ? ? typeName = "正在熱映";
? ? ? ? break;
? ? ? case "coming_soon":
? ? ? ? typeName = "即將上映";
? ? ? ? break;
? ? ? case "top250":
? ? ? ? typeName = "Top250";
? ? ? ? break;
? ? }
? ? //加載第一頁(yè)數(shù)據(jù)
? ? loadMoreData();
? }
? /**
? ?* 下拉刷新,必須異步async不然會(huì)報(bào)錯(cuò)
? ?*/
? 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,
? ? ? ? ? ? ),
? ? );
? }
? /**
? ?* 加載更多進(jìn)度條
? ?*/
? 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(
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "電影名稱(chēng):$title",
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? style: titleStyle,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? overflow: TextOverflow.ellipsis,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ),
? ? ? ? ? ? ? ? ? ? ? ? ? ? new Text(
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "電影類(lèi)型:$type",
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? style: titleStyle,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? overflow: TextOverflow.ellipsis,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ),
? ? ? ? ? ? ? ? ? ? ? ? ? ? new Text(
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "上映年份:$year",
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? style: titleStyle,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? overflow: TextOverflow.ellipsis,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ),
? ? ? ? ? ? ? ? ? ? ? ? ? ? new Text(
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "豆瓣評(píng)分:$score",
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? style: titleStyle,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? overflow: TextOverflow.ellipsis,
? ? ? ? ? ? ? ? ? ? ? ? ? ? )
? ? ? ? ? ? ? ? ? ? ? ? ? ],
? ? ? ? ? ? ? ? ? ? ? ? ),
? ? ? ? ? ? ? ? ? ? ? ),
? ? ? ? ? ? ? ? ? ? ),
? ? ? ? ? ? ? ? ? ],
? ? ? ? ? ? ? ? ),
? ? ? ? ? ? ? ),
? ? ? ? ? ? ? //分割線
? ? ? ? ? ? ? new Divider(height: 1)
? ? ? ? ? ? ],
? ? ? ? ? ),
? ? ? ? ));
? }
}以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
解決Android studio Error:(30, 31) 錯(cuò)誤: 程序包 不存在的問(wèn)題
這篇文章主要介紹了解決Android studio Error:(30, 31) 錯(cuò)誤: 程序包 不存在的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-03-03
Android項(xiàng)目實(shí)戰(zhàn)教程之高仿網(wǎng)易云音樂(lè)啟動(dòng)頁(yè)實(shí)例代碼
這篇文章主要給大家介紹了關(guān)于Android項(xiàng)目實(shí)戰(zhàn)教程之高仿網(wǎng)易云音樂(lè)啟動(dòng)頁(yè)的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2018-09-09
Android 點(diǎn)擊ImageButton時(shí)有“按下”的效果的實(shí)現(xiàn)
這篇文章主要介紹了 Android 點(diǎn)擊ImageButton時(shí)有“按下”的效果的實(shí)現(xiàn)的相關(guān)資料,需要的朋友可以參考下2017-03-03
Android 各國(guó)語(yǔ)言縮寫(xiě)及簡(jiǎn)稱(chēng)詳細(xì)介紹
android資源文件夾的寫(xiě)法規(guī)則: 語(yǔ)言縮寫(xiě)-國(guó)家地區(qū)縮寫(xiě),本文將詳細(xì)介紹Android 各國(guó)語(yǔ)言縮寫(xiě)及簡(jiǎn)稱(chēng),需要的朋友可以參考下2012-12-12
Android常用控件ImageSwitcher使用方法詳解
這篇文章主要為大家詳細(xì)介紹了Android常用控件ImageSwitcher的使用方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-08-08
Android實(shí)現(xiàn)簡(jiǎn)單圖片壓縮的方法
這篇文章主要介紹了Android實(shí)現(xiàn)簡(jiǎn)單圖片壓縮的方法,詳細(xì)分析了Android針對(duì)圖片的讀取、縮放及保存等操作技巧,需要的朋友可以參考下2016-06-06
Android開(kāi)發(fā)Intent跳轉(zhuǎn)傳遞list集合實(shí)現(xiàn)示例
這篇文章主要為大家介紹了Android開(kāi)發(fā)Intent跳轉(zhuǎn)傳遞list集合實(shí)現(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-07-07
Android實(shí)現(xiàn)簡(jiǎn)單下拉篩選框
這篇文章主要為大家詳細(xì)介紹了一款簡(jiǎn)單靈活的Android下拉篩選框,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-10-10
Android使用Kotlin和RxJava 2.×實(shí)現(xiàn)短信驗(yàn)證碼倒計(jì)時(shí)效果
本篇文章主要介紹了Android使用Kotlin和RxJava 2.×實(shí)現(xiàn)短信驗(yàn)證碼倒計(jì)時(shí)效果,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2017-12-12

