美文网首页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