美文网首页Flutter圈子flutter
Flutter下拉刷新,上拉加载更多数据

Flutter下拉刷新,上拉加载更多数据

作者: 树生1995 | 来源:发表于2018-10-11 10:47 被阅读10次

    下拉刷新

    很简单,直接使用 RefreshIndicator 组件, onRefresh 为重新获取数据的方法

      Widget build(BuildContext context) {
        return Scaffold(
          body: Container(
            padding: EdgeInsets.all(2.0),
            child: RefreshIndicator(
              onRefresh: _refresh,
              backgroundColor: Colors.blue,
              child: ListView.builder(
                      itemCount: _dataList.length,
                      itemBuilder: (context, index) {
                          return ListItem(_dataList[index]);
                      },
                    ),
            ),
          ),
        );
      }
      
      Future<Null> _refresh() async {
        _dataList.clear();
        await _loadFirstListData();
        return;
      }
    

    上拉加载更多

    我们先看一下效果

    下拉刷新
    • 让我们先从最原始的十条的数据开始
    class MyHomePage extends StatefulWidget {
      @override
      _MyHomePageState createState() => _MyHomePageState();
    }
    
    class _MyHomePageState extends State<MyHomePage> {
      List<int> items = List.generate(10, (i) => i);
    
      @override
      void initState() {
        super.initState();
      }
    
      @override
      void dispose() {
        super.dispose();
      }
    
      @override
      Widget build(BuildContext context) {
        return new Scaffold(
          appBar: AppBar(
            title: Text("Infinite ListView"),
          ),
          body: ListView.builder(
            itemCount: items.length,
            itemBuilder: (context, index) {
              return ListTile(title: new Text("Number $index"));
            },
          ),
        );
      }
    }
    
    • 现在我们要编写一个加载更多数据的方法,用来模拟 http 请求
    Future<List<int>> fakeRequest(int from, int to) async {
     return Future.delayed(Duration(seconds: 2), () {
       return List.generate(to - from, (i) => i + from);
     });
    }
    
    • 现在我们想要让用户将 ListView 滑动到最末端的触发 fakeRequest 来加载更多数据,最简单的实现方式就是使用 ScrollController 来完成,ScrollController 会监听滚动事件,当 ListView 滚动到末端的时候他会发出一个请求。在这里还有一件需要注意的事就是为了避免对服务器不断地请求,我们需要做一个标记 isPerformingRequest 只有当它为 false 的时候才允许对后台进行请求。
    class _MyHomePageState extends State<MyHomePage> {
      List<int> items = List.generate(10, (i) => i);
      ScrollController _scrollController = new ScrollController();
      bool isPerformingRequest = false;
    
      @override
      void initState() {
        super.initState();
        _scrollController.addListener(() {
          if (_scrollController.position.pixels == _scrollController.position.maxScrollExtent) {
            _getMoreData();
          }
        });
      }
    
      @override
      void dispose() {
        _scrollController.dispose();
        super.dispose();
      }
    
      _getMoreData() async {
        if (!isPerformingRequest) {
          setState(() => isPerformingRequest = true);
          List<int> newEntries = await fakeRequest(items.length, items.length + 10);
          setState(() {
            items.addAll(newEntries);
            isPerformingRequest = false;
          });
        }
      }
    
      @override
      Widget build(BuildContext context) {
        return new Scaffold(
          appBar: AppBar(
            title: Text("Infinite ListView"),
          ),
          body: ListView.builder(
            itemCount: items.length,
            itemBuilder: (context, index) {
              return ListTile(title: new Text("Number $index"));
            },
            controller: _scrollController,
          ),
        );
      }
    }
    

    如果你现在运行程序你将会看到我们的列表已经可以实现动态加载了,但是这距离我们的目标还很远,我们需要添加一些标志动作让用户这道请求已经开始。

    • 接下来我们要用到 CircularProgressIndicator 去完成这个加载标志
    Widget _buildProgressIndicator() {
      return new Padding(
        padding: const EdgeInsets.all(8.0),
        child: new Center(
          child: new Opacity(
            opacity: isPerformingRequest ? 1.0 : 0.0,
            child: new CircularProgressIndicator(),
          ),
        ),
      );
    }
    
    • 现在我们将这个加载标志放到我们的 ListView 中去,注意这里要给 itemCount 加出一块空间来放置我们的 _buildProgressIndicator
    @override
    Widget build(BuildContext context) {
      return new Scaffold(
        appBar: AppBar(
          title: Text("Infinite ListView"),
        ),
        body: ListView.builder(
          itemCount: items.length + 1,
          itemBuilder: (context, index) {
            if (index == items.length) {
              return _buildProgressIndicator();
            } else {
              return ListTile(title: new Text("Number $index"));
            }
          },
          controller: _scrollController,
        ),
      );
    }
    
    • 到这里加载更多数据的功能基本完成了,为了更加美观我们还要处理当没有请求到更多数据的时候动作,在这里我们添加一个动画没有更多数据的时候 ListView 向下移动覆盖正在加载更多数据的标志
    _getMoreData() async {
      if (!isPerformingRequest) {
        setState(() => isPerformingRequest = true);
        List<int> newEntries = await fakeRequest(items.length, items.length); //returns empty list
        if (newEntries.isEmpty) {
          double edge = 50.0;
          double offsetFromBottom = _scrollController.position.maxScrollExtent - _scrollController.position.pixels;
          if (offsetFromBottom < edge) {
            _scrollController.animateTo(
                _scrollController.offset - (edge -offsetFromBottom),
                duration: new Duration(milliseconds: 500),
                curve: Curves.easeOut);
          }
        }
        setState(() {
          items.addAll(newEntries);
          isPerformingRequest = false;
        });
      }
    }
    

    相关文章

      网友评论

      • Nealyang:咨询下,我想做一个上拉加载更多,触发后请求十条数据,但是现在的问题是,我第一页触底,触发了loadMore,发了请求,也渲染到页面了,但是新请求过来的数据,不是顺着我当前页面的位置往下平铺下去,而是直接塞到了我当前视图的上方,页面还是处于当前页面最底部
        树生1995:@Nealyang 首先要确认一件事,你在拿到新的数据之后,调用setState时有没有对List赋值,在这里是不能重新赋值的而应该调用items.addAll(newItems)向后追加新请求回来的数据newItems

      本文标题:Flutter下拉刷新,上拉加载更多数据

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