Flutter——下拉重新整理,上拉載入

江湖救急發表於2019-09-18

    我們在開發過程中,碰到列表頁展示資料,此時需用用到資料的重新整理,那麼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,使用的試用版,所以右上角有個水印)

Flutter——下拉重新整理,上拉載入

三:國際化顯示

細心的讀者肯定知道,為什麼我的下來重新整理,上拉載入提示語是英文的,怎麼回事?接下來我們來處理這個問題

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,重新執行,效果如下

Flutter——下拉重新整理,上拉載入


四:全域性重新整理配置

   全域性配置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))),
                ],
              ))
        ],
      ),
    );
  }
}
複製程式碼


六:結束語

如果示例有誤,煩請指正,不勝感激!

外掛地址:github.com/peng8350/fl…


相關文章