专注于 JetBrains IDEA 全家桶,永久激活,教程
持续更新 PyCharm,IDEA,WebStorm,PhpStorm,DataGrip,RubyMine,CLion,AppCode 永久激活教程

Flutter下拉刷新,上拉加载

我们在开发过程中,碰到列表页展示数据,此时需用用到数据的刷新,那么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,使用的试用版,所以右上角有个水印)

130_1.png

三:国际化显示

细心的读者肯定知道,为什么我的下来刷新,上拉加载提示语是英文的,怎么回事?接下来我们来处理这个问题

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

130_2.png

四:全局刷新配置

全局配置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…

文章永久链接:https://tech.souyunku.com/43171

未经允许不得转载:搜云库技术团队 » Flutter下拉刷新,上拉加载

JetBrains 全家桶,激活、破解、教程

提供 JetBrains 全家桶激活码、注册码、破解补丁下载及详细激活教程,支持 IntelliJ IDEA、PyCharm、WebStorm 等工具的永久激活。无论是破解教程,还是最新激活码,均可免费获得,帮助开发者解决常见激活问题,确保轻松破解并快速使用 JetBrains 软件。获取免费的破解补丁和激活码,快速解决激活难题,全面覆盖 2024/2025 版本!

联系我们联系我们