美文网首页
Flutter 下拉刷新上拉加载(电影app客户端案例)

Flutter 下拉刷新上拉加载(电影app客户端案例)

作者: xq9527 | 来源:发表于2020-08-30 00:36 被阅读0次

    前言:

    各位同学大家好,很久没有更新文章了,最近看了下flutter的下拉刷新和上拉加载,今天有时间就把之前帮朋友做的毕业设计的做到一半的电影app 加上 ,下拉刷新和上拉加载的功能 分享给大家,那么废话不多说我们正式开始

    准备工作:

    需要安装flutter的开发环境:大家可以去看看之前的教程:
    1 win系统flutter开发环境安装教程: https://www.jianshu.com/p/152447bc8718
    2 mac系统flutter开发环境安装教程:https://www.jianshu.com/p/bad2c35b41e3

    需要用到的三方库:

    dio: ^3.0.9
    toast: ^0.1.5
    请在pubspec.yaml 文件中添加依赖 如图:


    QQ截图20200829180130.png

    然后在控制台输入flutter pub get 下载依赖

    效果图:

    Screenrecorder-2020-08-29-19-16-21-704[00_00_06--00_00_26].gif Screenrecorder-2020-08-29-19-16-12-440[00_00_03--00_00_23].gif

    具体实现:

    QQ截图20200829192253.png

    底部tab切换

     bottomNavigationBar:Container(
              decoration: BoxDecoration(
                color: Colors.black
              ),
              height: 50,
              child: TabBar(
                labelStyle: TextStyle(
                  height: 0,
                  fontSize: 10
                ),
                tabs: <Widget>[
                  Tab(icon:  Icon(Icons.movie_filter),text: "正在热映",),
                  Tab(icon:  Icon(Icons.movie_creation),text: "即将上映",),
                  Tab(icon:  Icon(Icons.local_movies),text: "Top250",),
                ],
              ),
            ),
            body: TabBarView(
              children: <Widget>[
                Movielist(mt: "in_theaters",),
                Movielist(mt:"coming_soon"),
                Movielist(mt:"top250"),
              ],
            ),
    

    这边是用到了 bottomNavigationBar 组件里面嵌套3个tab组件来实现底部tab的切换之前有讲到过 ,然后我们在body里面 添加3个widget 来处理里上面电影列表的展示页面

        body: TabBarView(
              children: <Widget>[
                Movielist(mt: "in_theaters",),
                Movielist(mt:"coming_soon"),
                Movielist(mt:"top250"),
              ],
            ),
    

    这边因为3个列表页面的结构都是一样的,我们就用了一个页面分别传入不同的参数来实现即可

    侧边栏实现:

    效果图:


    QQ截图20200829192735.png

    我们在Scaffold脚手架框架里面添加了一个 Drawer组件实现的侧边栏 然后我们Drawer组件里面嵌套了一个listview组件并且使用listview的多布局来实现侧边栏的布局

         drawer:new Drawer(
              child: ListView.builder(
                  padding: EdgeInsets.all(0),
                  itemCount: 5,
                  itemBuilder: (BuildContext context, int position){
                    if(position==0){
                      return item1(position);
                    }else{
                      return item2(position);
                    }
                  })  ,
            ) ,
    

    当然在这里你也可以用其他组件来实现 (例如Column线性布局组件来排版也行)

    电影列表(下拉刷新 上拉加载 实现)

    效果图: Screenrecorder-2020-08-29-19-16-21-704[00_00_06--00_00_26].gif

    下拉刷新

    下来刷新我们需要在listview 的外面嵌套一层 RefreshIndicator 然后在RefreshIndicator里面实现onRefresh方法。

     @override
      Widget build(BuildContext context) {
        // TODO: implement build
        return Container(
          child:RefreshIndicator(
            onRefresh:_refresh ,
              child: ListView.builder(
                  controller: _controller, //指明控制器加载更多使用
                  itemCount: data==null?0:data.length,
                  itemBuilder: (BuildContext context, int position){
                    return itemWidget(position);
                  },
            ),
          )
        );
      }
    

    onRefresh方法的实现_refresh,注意这里必须使用async 不然报错

      Future  _refresh()async  {
        print("上拉加载");
          page=0;
          data.clear();
          getMovielist();
       return null;
      }
    

    异步加载数据 我们使用dio进行网络请求拿到数据,然后重写 setState方法刷新UI

      getMovielist()async {
        this.page++;
        int  offset=(page-1)*pagesize;
        Dio dio=new Dio();
        Response response=await dio.get("http://www.liulongbin.top:3005/api/v2/movie/${widget.mt}? 
      start=$offset&count=$pagesize");
         setState(() {
           var result=response.data.toString();
           print("result    ----   首次请求数据   ---   >  "+result);
           movieBean =MovieBean.fromJson(response.data);
           data.addAll(movieBean.subjects);
         });
      }
    

    这里我们通过MovieBean 数据模型类 讲json数据转成实体来获取里面的数据 ,我们调用list集合里面的
    addAll将每次加载的返回的list 集合全部都添加到 List<Subject>data=new List();我们定义的data集合里面就完成了上拉加载数据的目的

    上拉加载

    加载更多需要对ListView进行监听,所以需要进行监听器的设置,在State中进行监听器的初始化。

    //初始化滚动监听器,加载更多使用
    ScrollController _controller = new ScrollController();
    

    在构造器中设置监听

    _MovielistState() {
        //固定写法,初始化滚动监听器,加载更多使用
        _controller.addListener(() {
          var maxScroll = _controller.position.maxScrollExtent;
          var pixel = _controller.position.pixels;
          //
          if (maxScroll == pixel&& data.length < total) {
            setState(() {
              loadMoreText = "正在加载中...";
              loadMoreTextStyle =
              new TextStyle(color: const Color(0xFF4483f6), fontSize: 14.0);
            });
            getMovielist();
          } else {
            setState(() {
              loadMoreText = "没有更多数据";
              loadMoreTextStyle =
              new TextStyle(color: const Color(0xFF999999), fontSize: 14.0);
            });
          }
        });
      }
    

    然后我们在listview中添加监听controller方法

     child: ListView.builder(
                  controller: _controller, //指明控制器加载更多使用
                  itemCount: data==null?0:data.length,
                  itemBuilder: (BuildContext context, int position){
                    return itemWidget(position);
                  },
    

    至此我们的flutter下拉刷新和上拉加载就讲完了
    完整的movie_list 类代码示例

    import 'package:flutter/material.dart';
    import 'package:dio/dio.dart';
    import 'movie_bean.dart';
    import '../toast_util.dart';
    /**
     *
     * 创建人:xuqing
     * 创建时间:2020年8月2日16:25:52
     * 类说明:电影列表
     */
    class Movielist extends StatefulWidget {
      final String mt;
      Movielist({Key key,this.mt}) : super(key: key);
      @override
      _MovielistState createState() {
        return _MovielistState();
      }
    }
    class _MovielistState extends State<Movielist> {
      int  page=1;
      int pagesize=5;
      var  mlist=[];
      var total=0;
      int  datasize=0;
      MovieBean movieBean;
      Subject _subject;
      List<Subject>data=new List();
      String loadMoreText;
      ScrollController _controller = new ScrollController();
      _MovielistState() {
        //固定写法,初始化滚动监听器,加载更多使用
        _controller.addListener(() {
          var maxScroll = _controller.position.maxScrollExtent;
          var pixel = _controller.position.pixels;
          if (maxScroll == pixel&& data.length < total&&datasize<=5) {
              loadMoreText = "正在加载中...";
              ToastUtil.showInfo(context, loadMoreText);
              getMovielist();
          } else {
              loadMoreText = "没有更多数据";
              ToastUtil.showInfo(context, loadMoreText);
          }
        });
      }
      @override
      void initState() {
        super.initState();
        getMovielist();
      }
      @override
      void dispose() {
        super.dispose();
      }
      getMovielist()async {
        this.page++;
        int  offset=(page-1)*pagesize;
        Dio dio=new Dio();
        Response response=await dio.get("http://www.liulongbin.top:3005/api/v2/movie/${widget.mt}?start=$offset&count=$pagesize");
         setState(() {
           var result=response.data.toString();
           print("result    ----   首次请求数据   ---   >  "+result);
           movieBean =MovieBean.fromJson(response.data);
           data.addAll(movieBean.subjects);
           total=movieBean.total;
           datasize=movieBean.subjects.length;
           print("datasize   ---  >  "+datasize.toString());
         });
      }
      @override
      Widget build(BuildContext context) {
        // TODO: implement build
        return data.length==0?
            new Center(child: new CircularProgressIndicator())
            :Container(
            child:RefreshIndicator(
              onRefresh:_refresh ,
              child: ListView.builder(
                controller: _controller, //指明控制器加载更多使用
                itemCount: data==null?0:data.length,
                itemBuilder: (BuildContext context, int position){
                    return itemWidget(position);
                },
              ),
            )
        );
      }
      Future  _refresh()async  {
        print("上拉加载");
          page=0;
          data.clear();
          getMovielist();
       return null;
      }
      /**
       * item布局
       *
       */
      Widget  itemWidget(int index){
        _subject=data[index];
        Rating rating=_subject.rating;
        if(_subject==null){
          return Container(
            child: Center(
              child: Text("暂时没有数据",style: TextStyle(
                  color: Colors.red,fontSize: 30
              ),),
            ),
          );
        }else{
          return GestureDetector(
            child:Container(
              height: 200,
              decoration: BoxDecoration(color: Colors.white,border: Border(
                top: BorderSide(
                  color: Colors.black
                )
              )),
              child:Row(
            children: <Widget>[
            Image.network(_subject.images.small,
              width: 130,
              height: 180,
              fit: BoxFit.fill,),
            Container(
              height: 200,
              child:Column(
                mainAxisAlignment: MainAxisAlignment.spaceAround,
                crossAxisAlignment: CrossAxisAlignment.start,
                children: <Widget>[
                  Text("电影名称:"+_subject.title),
                  Text("上映年份"+_subject.year),
                  Text("电影类型:"+_subject.genres.join(",")),
                  Text("豆瓣评分:"+_subject.rating.average+"分"),
                  Row(
                    children: <Widget>[
                      Text("主要演员"),
                      Container(
                        width: 30,
                        height: 30,
                        child: Image.network(_subject.images.small),
                      ),
                      Container(
                        width: 30,
                        height: 30,
                        child: Image.network(_subject.images.large),
                      ),
                      Container(
                        width: 30,
                        height: 30,
                        child:  Image.network(_subject.images.medium)
                      )
                    ],
                  )
                ],
              ),
            )
            ],
            ) ,
         )
        );
        }
      }
    }
    

    最后总结:

    flutter中下来刷新和上来加载主要是处理好 RefreshIndicator 外层嵌套的组件里面的onRefresh 刷新方法和listview 组件中的 controller 滑动监听 就可以实现了比起原生要简单很多,当然我们也可以用一些三方库来实现下来刷新和上拉加载 例如( dynamic_list_view 组件)等等 有兴趣学的的同学可以私下多多交流 最后希望我的文章能帮助到各位解决问题 ,以后我还会贡献更多有用的代码分享给大家。各位同学如果觉得文章还不错 ,麻烦给关注和star,小弟在这里谢过啦

    项目地址:

    码云 :https://gitee.com/qiuyu123/flutter_movie.git

    相关文章

      网友评论

          本文标题:Flutter 下拉刷新上拉加载(电影app客户端案例)

          本文链接:https://www.haomeiwen.com/subject/ntdjsktx.html