Flutter如何實現下拉重新整理和上拉載入更多
阿新 • • 發佈:2019-01-04
- 效果
- 下拉重新整理
如果實現下拉重新整理,必須藉助RefreshIndicator,在listview外面包裹一層RefreshIndicator,然後在RefreshIndicator裡面實現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方法的實現_pullToRefresh,注意這裡必須使用async 不然報錯
/**
* 下拉重新整理,必須非同步async不然會報錯
*/
Future _pullToRefresh() async {
currentPage = 0;
movieList.clear();
loadMoreData();
return null;
}
非同步載入資料,注意:在Flutter中重新整理資料使用的是setState,不然無效,資料不會重新整理;資料的獲取需要使用[]取值,不能使用物件“ . ”的取值方法!
//載入列表資料 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進行監聽,所以需要進行監聽器的設定,在State中進行監聽器的初始化。
//初始化滾動監聽器,載入更多使用
ScrollController _controller = new ScrollController();
在構造器中設定監聽
//固定寫法,初始化滾動監聽器,載入更多使用 _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 = "沒有更多資料"; loadMoreTextStyle = new TextStyle(color: const Color(0xFF999999), fontSize: 14.0); }); } });
在listView中新增監聽controller方法
自此,Flutter如何實現下拉重新整理和上拉載入更多完成…
- 整個列表頁面程式碼參考如下:
import 'package:flutter/material.dart';
import 'package:dio/dio.dart';
import 'package:douban/pages/movie/movieDetail.dart';
class MovieList extends StatefulWidget {
String movieType;
//構造器傳遞資料(並且接收上個頁面傳遞的資料)
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; //總條數
String loadMoreText = "沒有更多資料";
TextStyle loadMoreTextStyle =
new TextStyle(color: const Color(0xFF999999), fontSize: 14.0);
TextStyle titleStyle =
new TextStyle(color: const Color(0xFF757575), fontSize: 14.0);
//初始化滾動監聽器,載入更多使用
ScrollController _controller = new ScrollController();
/**
* 構造器接收(MovieList)資料
*/
MovieListState({Key key, this.movieType}) {
//固定寫法,初始化滾動監聽器,載入更多使用
_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 = "沒有更多資料";
loadMoreTextStyle =
new TextStyle(color: const Color(0xFF999999), fontSize: 14.0);
});
}
});
}
//載入列表資料
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;
}
//載入第一頁資料
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)
],
),
));
}
}