我們在開發過程中,碰到列表頁展示資料,此時需用用到資料的重新整理,那麼Flutter如何實現這個呢?今天我們使用一個外掛來實現下拉重新整理,上拉載入
一:準備工作
1,新增依賴
pull_to_refresh: ^1.5.6
複製程式碼
2,獲取依賴
flutter pub get複製程式碼
3,在需要使用的檔案中匯入依賴
import 'package:pull_to_refresh/pull_to_refresh.dart';
複製程式碼
二:案例演示
1,建立列表子項元件
class Item extends StatelessWidget {
Color color;
IconData icon;
String mainTitle;
String subTitle;
String des;
int readCount;
Item(this.color, this.icon, this.mainTitle, this.subTitle, this.des,
this.readCount);
@override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.fromLTRB(10.0, 5.0, 10.0, 5.0),
height: 90.0,
child: Row(
children: <Widget>[
Container(
width: 90.0,
color: color,
alignment: Alignment.center,
child: Icon(icon, color: Colors.white),
),
SizedBox(width: 10),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Expanded(
child: Text(mainTitle,
style: TextStyle(
fontWeight: FontWeight.bold, fontSize: 18.0))),
Expanded(child: Text(subTitle, style: TextStyle(fontSize: 14.0))),
Expanded(
child: Text(
des,
style: TextStyle(fontSize: 13.0),
overflow: TextOverflow.ellipsis,
)),
Expanded(
child: Text("閱讀量:${readCount.toString()}",
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 14.0,
color: Colors.redAccent))),
],
))
],
),
);
}
}複製程式碼
2,建立資料模型
class ItemModel{
Color _color;
IconData _icon;
String _mainTitle;
String _subTitle;
String _des;
int _readCount;
ItemModel(this._color, this._icon, this._mainTitle, this._subTitle, this._des,
this._readCount);
int get readCount => _readCount;
set readCount(int value) {
_readCount = value;
}
String get des => _des;
set des(String value) {
_des = value;
}
String get subTitle => _subTitle;
set subTitle(String value) {
_subTitle = value;
}
String get mainTitle => _mainTitle;
set mainTitle(String value) {
_mainTitle = value;
}
IconData get icon => _icon;
set icon(IconData value) {
_icon = value;
}
Color get color => _color;
set color(Color value) {
_color = value;
}
}複製程式碼
3,建立資料提供類
class ListData{
static List<Widget> getList(){
List<Widget> models=[];
ItemModel model1= ItemModel(Colors.red, Icons.airplanemode_active, "軍事新聞", "俄軍大秀戰略",
"醞釀已久的俄羅斯“中部-2019”戰略演習於16日正式啟動", 2999);
ItemModel model2= ItemModel(Colors.red, Icons.airplanemode_active, "軍事新聞", "俄“中部”演習",
"俄羅斯衛星網報導稱,俄羅斯國防部長紹伊古表示,“中央-2019”戰略演習是", 4588);
ItemModel model3= ItemModel(Colors.red, Icons.airplanemode_active, "軍事新聞", "中國2.7萬噸塢登艦",
"據印度新德里電視臺16日報導,印度海軍發現7艘中國軍艦在印度洋", 7777);
ItemModel model4= ItemModel(Colors.red, Icons.airplanemode_active, "軍事新聞", "針對中國?",
"美國空軍著力打造軍用5G網路,5G+VR,飛行員無需上天就能操控戰機;美軍瀕海", 8888);
ItemModel model5= ItemModel(Colors.red, Icons.airplanemode_active, "軍事新聞", "“凱旋”防空導彈系統",
"俄羅斯衛星通訊社報導,俄羅斯北方艦隊(Russian Northern Fleet)新聞處", 9999);
ItemModel model6= ItemModel(Colors.red, Icons.airplanemode_active, "軍事新聞", "火箭軍還有騎兵連",
"迅速對禁區“敵特分子”活動區域進行偵察定位,戰鬥小分隊", 104754);
ItemModel model7= ItemModel(Colors.red, Icons.airplanemode_active, "軍事新聞", "偵察兵跨越冰川",
"在海拔5000多米的雪域高原,第77集團軍某合成旅的偵察兵們正在進行野外駐訓", 47545);
ItemModel model8= ItemModel(Colors.red, Icons.airplanemode_active, "軍事新聞", "香港被護商船",
"新京報快訊 據北海艦隊官微訊息:“感謝海軍!”“祖國萬歲!”,當地時", 124574);
models.add(Item(model1.color, model1.icon, model1.mainTitle, model1.subTitle, model1.des, model1.readCount));
models.add(Item(model2.color, model2.icon, model2.mainTitle, model2.subTitle, model2.des, model2.readCount));
models.add(Item(model3.color, model3.icon, model3.mainTitle, model3.subTitle, model3.des, model3.readCount));
models.add(Item(model4.color, model4.icon, model4.mainTitle, model4.subTitle, model4.des, model4.readCount));
models.add(Item(model5.color, model5.icon, model5.mainTitle, model5.subTitle, model5.des, model5.readCount));
models.add(Item(model6.color, model6.icon, model6.mainTitle, model6.subTitle, model6.des, model6.readCount));
models.add(Item(model7.color, model7.icon, model7.mainTitle, model7.subTitle, model7.des, model7.readCount));
models.add(Item(model8.color, model8.icon, model8.mainTitle, model8.subTitle, model8.des, model8.readCount));
return models;
}
}複製程式碼
4,建立重新整理元件
class Pulltorefresh extends StatefulWidget {
@override
_PulltorefreshState createState() => _PulltorefreshState();
}
class _PulltorefreshState extends State<Pulltorefresh> {
List<Widget> datas=ListData.getList();
RefreshController _controller=RefreshController(initialRefresh: false);
void _onRefresh() async{
await Future.delayed(Duration(milliseconds: 1000));
_controller.refreshCompleted();
}
void _onLoading() async{
await Future.delayed(Duration(milliseconds: 1500));
ItemModel model=ItemModel(getRandomColor(), Icons.airplanemode_active, "軍事新聞", "俄軍大秀戰略",
"醞釀已久的俄羅斯“中部-2019”戰略演習於16日正式啟動", 5000);
this.datas.add(Item(getRandomColor(), model.icon, model.mainTitle, model.subTitle, model.des, model.readCount));
this.datas.add(Item(getRandomColor(), model.icon, model.mainTitle, model.subTitle, model.des, model.readCount));
this.datas.add(Item(getRandomColor(), model.icon, model.mainTitle, model.subTitle, model.des, model.readCount));
this.datas.add(Item(getRandomColor(), model.icon, model.mainTitle, model.subTitle, model.des, model.readCount));
this.datas.add(Item(getRandomColor(), model.icon, model.mainTitle, model.subTitle, model.des, model.readCount));
this.datas.add(Item(getRandomColor(), model.icon, model.mainTitle, model.subTitle, model.des, model.readCount));
this.datas.add(Item(getRandomColor(), model.icon, model.mainTitle, model.subTitle, model.des, model.readCount));
this.datas.add(Item(getRandomColor(), model.icon, model.mainTitle, model.subTitle, model.des, model.readCount));
if(mounted)
setState(() {
});
_controller.loadComplete();
}
@override
Widget build(BuildContext context) {
Widget _itemBuilder(BuildContext context, int position) {
return Card(child: this.datas[position]);
}
return Scaffold(
appBar: AppBar(
title: Text("Pulltorefresh"),
),
body: SmartRefresher(
enablePullDown: true,
enablePullUp: true,
header: WaterDropHeader(),
footer: ClassicFooter(
loadStyle: LoadStyle.ShowAlways,
completeDuration: Duration(microseconds: 50),
),
onRefresh: _onRefresh,
onLoading: _onLoading,
controller: _controller,
child: ListView.builder(itemBuilder: _itemBuilder,itemCount: this.datas.length),
),
);
}
Color getRandomColor(){
List<Color> colors=[Colors.deepOrange,Colors.amber,Colors.cyan,Colors.green,Colors.red,Colors.yellow];
int randomValue=Random().nextInt(colors.length);
if(randomValue==colors.length){
randomValue=colors.length-1;
}
return colors[randomValue];
}
}複製程式碼
說明:
- 將我們自己的child外面包裹一層SmartRefresher,這個是必須的
- 屬性enablePullDown,允許下拉重新整理
- 屬性enablePullUp,允許上拉載入
- 屬性header,代表下拉重新整理頭部樣式
- 屬性footer,代表上拉載入底部樣式
- 屬性onRefresh,代表下拉重新整理的回撥
- 屬性onLoading,代表上拉載入的回撥
- 屬性controller,重新整理控制元件的控制器,用來處理回撥狀態等
案例中,我們在下拉重新整理的時候延時1秒鐘模擬非同步網路請求資料,1秒鐘之後通過controller改變header的狀態;在上拉載入的時候模擬1.5秒的非同步網路請求資料,新增了8條資料,1.5秒之後通過controller改變footer的狀態。
效果演示(初次使用gif軟體是傲軟GIF,使用的試用版,所以右上角有個水印)
三:國際化顯示
細心的讀者肯定知道,為什麼我的下來重新整理,上拉載入提示語是英文的,怎麼回事?接下來我們來處理這個問題
1,新增SDK
flutter_localizations:
sdk: flutter
複製程式碼
2,獲取依賴
flutter pub get複製程式碼
3,在main.dart檔案中匯入依賴
import 'package:flutter_localizations/flutter_localizations.dart';
複製程式碼
4,在main.dart的MateriaApp裡面新增如下程式碼
localizationsDelegates: [
// 這行是關鍵
RefreshLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalMaterialLocalizations.delegate
],
supportedLocales: [
const Locale('en'),
const Locale('zh'),
],
localeResolutionCallback:
(Locale locale, Iterable<Locale> supportedLocales) {
//print("change language");
return locale;
},
複製程式碼
5,重新執行,效果如下
四:全域性重新整理配置
全域性配置RefreshConfiguration,配置子樹下的所有SmartRefresher表現,一般存放於MaterialApp的根部
// 全域性配置子樹下的SmartRefresher,下面列舉幾個特別重要的屬性
RefreshConfiguration(
headerBuilder: () => WaterDropHeader(), // 配置預設頭部指示器,假如你每個頁面的頭部指示器都一樣的話,你需要設定這個
footerBuilder: () => ClassicFooter(), // 配置預設底部指示器
headerTriggerDistance: 80.0, // 頭部觸發重新整理的越界距離
springDescription:SpringDescription(stiffness: 170, damping: 16, mass: 1.9), // 自定義回彈動畫,三個屬性值意義請查詢flutter api
maxOverScrollExtent :100, //頭部最大可以拖動的範圍,如果發生衝出檢視範圍區域,請設定這個屬性
maxUnderScrollExtent:0, // 底部最大可以拖動的範圍
enableScrollWhenRefreshCompleted: true, //這個屬性不相容PageView和TabBarView,如果你特別需要TabBarView左右滑動,你需要把它設定為true
enableLoadingWhenFailed : true, //在載入失敗的狀態下,使用者仍然可以通過手勢上拉來觸發載入更多
hideFooterWhenNotFull: false, // Viewport不滿一屏時,禁用上拉載入更多功能
enableBallisticLoad: true, // 可以通過慣性滑動觸發載入更多
child: MaterialApp(
........
)
);複製程式碼
五:完整程式碼示例
1,main.dart
import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:pull_to_refresh/pull_to_refresh.dart';
import 'pages/Pulltorefresh.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return RefreshConfiguration(
child: MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.red,
),
localizationsDelegates: [
// 這行是關鍵
RefreshLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalMaterialLocalizations.delegate
],
supportedLocales: [
const Locale('en'),
const Locale('zh'),
],
localeResolutionCallback:
(Locale locale, Iterable<Locale> supportedLocales) {
//print("change language");
return locale;
},
home: Pulltorefresh(),
),
);
}
}
複製程式碼
2,Pulltorefresh.dart
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:pull_to_refresh/pull_to_refresh.dart';
///create time : 2019/9/18/018 8:38
///create by : Administrator
///des:重新整理元件
class Pulltorefresh extends StatefulWidget {
@override
_PulltorefreshState createState() => _PulltorefreshState();
}
class _PulltorefreshState extends State<Pulltorefresh> {
List<Widget> datas=ListData.getList();
RefreshController _controller=RefreshController(initialRefresh: false);
void _onRefresh() async{
await Future.delayed(Duration(milliseconds: 1000));
_controller.refreshCompleted();
}
void _onLoading() async{
await Future.delayed(Duration(milliseconds: 1500));
ItemModel model=ItemModel(getRandomColor(), Icons.airplanemode_active, "軍事新聞", "俄軍大秀戰略",
"醞釀已久的俄羅斯“中部-2019”戰略演習於16日正式啟動", 5000);
this.datas.add(Item(getRandomColor(), model.icon, model.mainTitle, model.subTitle, model.des, model.readCount));
this.datas.add(Item(getRandomColor(), model.icon, model.mainTitle, model.subTitle, model.des, model.readCount));
this.datas.add(Item(getRandomColor(), model.icon, model.mainTitle, model.subTitle, model.des, model.readCount));
this.datas.add(Item(getRandomColor(), model.icon, model.mainTitle, model.subTitle, model.des, model.readCount));
this.datas.add(Item(getRandomColor(), model.icon, model.mainTitle, model.subTitle, model.des, model.readCount));
this.datas.add(Item(getRandomColor(), model.icon, model.mainTitle, model.subTitle, model.des, model.readCount));
this.datas.add(Item(getRandomColor(), model.icon, model.mainTitle, model.subTitle, model.des, model.readCount));
this.datas.add(Item(getRandomColor(), model.icon, model.mainTitle, model.subTitle, model.des, model.readCount));
if(mounted)
setState(() {
});
_controller.loadComplete();
}
@override
Widget build(BuildContext context) {
Widget _itemBuilder(BuildContext context, int position) {
return Card(child: this.datas[position]);
}
return Scaffold(
appBar: AppBar(
title: Text("Pulltorefresh"),
),
body: SmartRefresher(
enablePullDown: true,
enablePullUp: true,
header: WaterDropHeader(),
footer: ClassicFooter(
loadStyle: LoadStyle.ShowAlways,
completeDuration: Duration(microseconds: 50),
),
onRefresh: _onRefresh,
onLoading: _onLoading,
controller: _controller,
child: ListView.builder(itemBuilder: _itemBuilder,itemCount: this.datas.length),
),
);
}
Color getRandomColor(){
List<Color> colors=[Colors.deepOrange,Colors.amber,Colors.cyan,Colors.green,Colors.red,Colors.yellow];
int randomValue=Random().nextInt(colors.length);
if(randomValue==colors.length){
randomValue=colors.length-1;
}
return colors[randomValue];
}
}
class ItemModel{
Color _color;
IconData _icon;
String _mainTitle;
String _subTitle;
String _des;
int _readCount;
ItemModel(this._color, this._icon, this._mainTitle, this._subTitle, this._des,
this._readCount);
int get readCount => _readCount;
set readCount(int value) {
_readCount = value;
}
String get des => _des;
set des(String value) {
_des = value;
}
String get subTitle => _subTitle;
set subTitle(String value) {
_subTitle = value;
}
String get mainTitle => _mainTitle;
set mainTitle(String value) {
_mainTitle = value;
}
IconData get icon => _icon;
set icon(IconData value) {
_icon = value;
}
Color get color => _color;
set color(Color value) {
_color = value;
}
}
class ListData{
static List<Widget> getList(){
List<Widget> models=[];
ItemModel model1= ItemModel(Colors.red, Icons.airplanemode_active, "軍事新聞", "俄軍大秀戰略",
"醞釀已久的俄羅斯“中部-2019”戰略演習於16日正式啟動", 2999);
ItemModel model2= ItemModel(Colors.red, Icons.airplanemode_active, "軍事新聞", "俄“中部”演習",
"俄羅斯衛星網報導稱,俄羅斯國防部長紹伊古表示,“中央-2019”戰略演習是", 4588);
ItemModel model3= ItemModel(Colors.red, Icons.airplanemode_active, "軍事新聞", "中國2.7萬噸塢登艦",
"據印度新德里電視臺16日報導,印度海軍發現7艘中國軍艦在印度洋", 7777);
ItemModel model4= ItemModel(Colors.red, Icons.airplanemode_active, "軍事新聞", "針對中國?",
"美國空軍著力打造軍用5G網路,5G+VR,飛行員無需上天就能操控戰機;美軍瀕海", 8888);
ItemModel model5= ItemModel(Colors.red, Icons.airplanemode_active, "軍事新聞", "“凱旋”防空導彈系統",
"俄羅斯衛星通訊社報導,俄羅斯北方艦隊(Russian Northern Fleet)新聞處", 9999);
ItemModel model6= ItemModel(Colors.red, Icons.airplanemode_active, "軍事新聞", "火箭軍還有騎兵連",
"迅速對禁區“敵特分子”活動區域進行偵察定位,戰鬥小分隊", 104754);
ItemModel model7= ItemModel(Colors.red, Icons.airplanemode_active, "軍事新聞", "偵察兵跨越冰川",
"在海拔5000多米的雪域高原,第77集團軍某合成旅的偵察兵們正在進行野外駐訓", 47545);
ItemModel model8= ItemModel(Colors.red, Icons.airplanemode_active, "軍事新聞", "香港被護商船",
"新京報快訊 據北海艦隊官微訊息:“感謝海軍!”“祖國萬歲!”,當地時", 124574);
models.add(Item(model1.color, model1.icon, model1.mainTitle, model1.subTitle, model1.des, model1.readCount));
models.add(Item(model2.color, model2.icon, model2.mainTitle, model2.subTitle, model2.des, model2.readCount));
models.add(Item(model3.color, model3.icon, model3.mainTitle, model3.subTitle, model3.des, model3.readCount));
models.add(Item(model4.color, model4.icon, model4.mainTitle, model4.subTitle, model4.des, model4.readCount));
models.add(Item(model5.color, model5.icon, model5.mainTitle, model5.subTitle, model5.des, model5.readCount));
models.add(Item(model6.color, model6.icon, model6.mainTitle, model6.subTitle, model6.des, model6.readCount));
models.add(Item(model7.color, model7.icon, model7.mainTitle, model7.subTitle, model7.des, model7.readCount));
models.add(Item(model8.color, model8.icon, model8.mainTitle, model8.subTitle, model8.des, model8.readCount));
return models;
}
}
class Item extends StatelessWidget {
Color color;
IconData icon;
String mainTitle;
String subTitle;
String des;
int readCount;
Item(this.color, this.icon, this.mainTitle, this.subTitle, this.des,
this.readCount);
@override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.fromLTRB(10.0, 5.0, 10.0, 5.0),
height: 90.0,
child: Row(
children: <Widget>[
Container(
width: 90.0,
color: color,
alignment: Alignment.center,
child: Icon(icon, color: Colors.white),
),
SizedBox(width: 10),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Expanded(
child: Text(mainTitle,
style: TextStyle(
fontWeight: FontWeight.bold, fontSize: 18.0))),
Expanded(child: Text(subTitle, style: TextStyle(fontSize: 14.0))),
Expanded(
child: Text(
des,
style: TextStyle(fontSize: 13.0),
overflow: TextOverflow.ellipsis,
)),
Expanded(
child: Text("閱讀量:${readCount.toString()}",
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 14.0,
color: Colors.redAccent))),
],
))
],
),
);
}
}
複製程式碼
六:結束語
如果示例有誤,煩請指正,不勝感激!