美文网首页Flutter
Flutter基础组件(3-2)-ListView数据加载(刷新

Flutter基础组件(3-2)-ListView数据加载(刷新

作者: 周灬 | 来源:发表于2019-12-05 14:18 被阅读0次

    1.模仿安卓的刷新样式

    这部分的文章感谢晓果博客,原文链接https://blog.csdn.net/huangxiaoguo1/article/details/85603172

    1.1 下拉刷新

    如果实现下拉刷新,可以借助RefreshIndicator,在listview外面包裹一层RefreshIndicator,然后在RefreshIndicator里面实现onRefresh方法。

     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,
          ),
        );
      }
    

    onRefresh方法的实现_pullToRefresh,注意这里必须使用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"];
        });
      }
    

    1.2 上拉加载更多

    加载更多需要对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方法,

    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,
          ),
        );
      }
    

    完整的代码

    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)
                ],
              ),
            ));
      }
    }
    

    2.模仿iOS的刷新样式

    模仿iOS的刷新,我们可以使用github上flutter_easyrefresh.
    我们先简单看一个例子:

    import 'dart:async';
    import 'package:flutter/material.dart';
    import 'package:flutter_easyrefresh/easy_refresh.dart';
    import 'package:flutter_easyrefresh/bezier_circle_header.dart';//如果要使用炫酷的样式需要引入,不同的样式引入不同的文件,详见官方api
    import 'package:flutter_easyrefresh/bezier_bounce_footer.dart';//如果要使用炫酷的样式需要引入,不同的样式引入不同的文件,详见官方api
    
    void main() => runApp(MyApp());
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return new MaterialApp(
          // App名字
          title: 'EasyRefresh',
          // App主题
          theme: new ThemeData(
            primarySwatch: Colors.orange,
          ),
          // 主页
          home: BasicPage(),
        );
      }
    }
    
    class BasicPage extends StatefulWidget {
      @override
      _BasicPageState createState() => _BasicPageState();
    }
    
    class _BasicPageState extends State<BasicPage> {
      List<String> addStr = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "0"];
      List<String> str = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "0"];
      GlobalKey<EasyRefreshState> _easyRefreshKey =
      new GlobalKey<EasyRefreshState>();
      GlobalKey<RefreshHeaderState> _headerKey =
      new GlobalKey<RefreshHeaderState>();
      GlobalKey<RefreshFooterState> _footerKey =
      new GlobalKey<RefreshFooterState>();
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text("EasyRefresh"),
          ),
          body: Center(
              child: new EasyRefresh(
                key: _easyRefreshKey,
                refreshHeader: BezierCircleHeader(
                  key: _headerKey,
                  color: Theme
                      .of(context)
                      .scaffoldBackgroundColor,
                ),
                refreshFooter: BezierBounceFooter(
                  key: _footerKey,
                  color: Theme
                      .of(context)
                      .scaffoldBackgroundColor,
                ),
                child: new ListView.builder(
                  //ListView的Item
                    itemCount: str.length,
                    itemBuilder: (BuildContext context, int index) {
                      return new Container(
                          height: 70.0,
                          child: Card(
                            child: new Center(
                              child: new Text(
                                str[index],
                                style: new TextStyle(fontSize: 18.0),
                              ),
                            ),
                          ));
                    }),
                onRefresh: () async {
                  await new Future.delayed(const Duration(seconds: 1), () {
                    setState(() {
                      str.clear();
                      str.addAll(addStr);
                    });
                  });
                },
                loadMore: () async {
                  await new Future.delayed(const Duration(seconds: 1), () {
                    if (str.length < 20) {
                      setState(() {
                        str.addAll(addStr);
                      });
                    }
                  });
                },
              )),
    //      persistentFooterButtons: <Widget>[
    //        FlatButton(
    //            onPressed: () {
    //              _easyRefreshKey.currentState.callRefresh();
    //            },
    //            child: Text("refresh", style: TextStyle(color: Colors.black))),
    //        FlatButton(
    //            onPressed: () {
    //              _easyRefreshKey.currentState.callLoadMore();
    //            },
    //            child: Text("loadMore", style: TextStyle(color: Colors.black)))
    //      ], // This trailing comma makes auto-formatting nicer for build methods.
        );
      }
    }
    

    我们需要先定义三种key来表示每一种操作:

    GlobalKey<EasyRefreshState> _easyRefreshKey =
      new GlobalKey<EasyRefreshState>();
      GlobalKey<RefreshHeaderState> _headerKey =
      new GlobalKey<RefreshHeaderState>();
      GlobalKey<RefreshFooterState> _footerKey =
      new GlobalKey<RefreshFooterState>();
    
                                想了解更多Flutter学习知识请联系:QQ(814299221)
    

    相关文章

      网友评论

        本文标题:Flutter基础组件(3-2)-ListView数据加载(刷新

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