美文网首页Flutter
【Flutter】开发之进阶Widget(五)

【Flutter】开发之进阶Widget(五)

作者: 欢子3824 | 来源:发表于2019-06-25 17:59 被阅读14次

    前言

    在上一篇中,我们学习了controller、点击事件onPressedGestureDetectorTabBarPageView联动的使用,这一篇,我们来说说ListView的上拉刷新、下拉加载和轮播图。

    刷新控件

    下拉刷新

    官方为我们提供了RefreshIndicator,主要有colorbackgroundColordisplacementonRefresh等属性

            RefreshIndicator(
            //刷新进度条颜色
            color: Colors.black45,
            //背景色
            backgroundColor: Colors.blue,
            //触发下拉刷新的距离 默认40
            displacement: 40,
            //下拉回调方法,方法需要有async和await关键字,没有await,刷新图标立马消失,没有async,刷新图标不会消失
            onRefresh: refresh,
            child: ListView.separated(
              itemBuilder: ((context, index) {
                return MoveItem();
              }),
              separatorBuilder: (context, index) {
                return Divider(
                  color: Colors.black45,
                  height: 10,
                );
              },
              itemCount: count,
            ),
          ),
    
      int count = 2;
    
      Future refresh() async {
        await Future.delayed(Duration(seconds: 3), () {
          setState(() {
            count = 10;
          });
        });
      }
    

    效果图如下


    20190625_174848.gif

    上拉加载

    上拉加载的话,需要使用ListViewcontroller属性

    final ScrollController _scrollController = new ScrollController();
    
     @override
      void initState() {
        ///增加滑动监听
        _scrollController.addListener(() {
          ///判断当前滑动位置是不是到达底部,触发加载更多回调
          if (_scrollController.position.pixels ==
              _scrollController.position.maxScrollExtent) {
            setState(() {
              count += 5;
            });
          }
        });
    
        super.initState();
      }
    
      @override
      void dispose() {
        super.dispose();
        _scrollController.dispose();
      }
    

    然后将_scrollController设置给ListView
    当我们运行时却发现,不仅不能上拉加载,连下拉刷新也失效了!
    这是因为,RefreshIndicatorScrollController有兼容性问题,当然官方也给出了解决办法,给ListView添加如下代码:
    physics: const AlwaysScrollableScrollPhysics()
    效果图如下

    20190625_175404.gif

    虽然说功能实现了,但是感觉效果有点怪怪的,新的item出现前应该有个过渡。
    思路如下,当触发上拉加载时,给ListView添加一个加载中的item,当加载完成后,再移除。
    先定义个变量,bool loadMore = false;
    当触发上拉加载时,设置为true

      @override
      void initState() {
        ///增加滑动监听
        _scrollController.addListener(() {
          ///判断当前滑动位置是不是到达底部,触发加载更多回调
          if (_scrollController.position.pixels ==
              _scrollController.position.maxScrollExtent) {
            setState(() {
              loadMore = true;
            });
            getMore();
          }
        });
        super.initState();
      }
    

    加载完成时,设置为false

      Future getMore() async {
        await Future.delayed(Duration(seconds: 3), () {
          setState(() {
            loadMore = false;
            count += 5;
          });
        });
      }
    

    这时,item就不能是固定的了

      Widget getItem(int index) {
        if (loadMore && index == count) {
          return LoadMoreItem();
        } else {
          return MoveItem();
        }
      }
    

    包括count

      int getItemCount() {
        if (loadMore) {
          return count + 1;
        } else {
          return count;
        }
      }
    

    效果图如下


    20190625_174934.gif

    完整代码如下

    class ListViewDemo extends StatefulWidget {
      @override
      _ReListViewDemoState createState() => _ReListViewDemoState();
    }
    
    class _ReListViewDemoState extends State<ListViewDemo> {
      int count = 2;
      final ScrollController _scrollController = new ScrollController();
    
      bool loadMore = false;
    
      Future refresh() async {
        await Future.delayed(Duration(seconds: 3), () {
          setState(() {
            count = 10;
          });
        });
      }
    
      Future getMore() async {
        await Future.delayed(Duration(seconds: 3), () {
          setState(() {
            loadMore = false;
            count += 5;
          });
        });
      }
    
      @override
      void initState() {
        ///增加滑动监听
        _scrollController.addListener(() {
          ///判断当前滑动位置是不是到达底部,触发加载更多回调
          if (_scrollController.position.pixels ==
              _scrollController.position.maxScrollExtent) {
            setState(() {
              loadMore = true;
            });
            getMore();
          }
        });
        super.initState();
      }
    
      Widget getItem(int index) {
        if (loadMore && index == count) {
          return LoadMoreItem();
        } else {
          return MoveItem();
        }
      }
    
      int getItemCount() {
        if (loadMore) {
          return count + 1;
        } else {
          return count;
        }
      }
    
      @override
      void dispose() {
        super.dispose();
        _scrollController.dispose();
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text('ListViewDemo'),
            centerTitle: true,
            brightness: Brightness.dark,
          ),
          body: RefreshIndicator(
            //刷新进度条颜色
            color: Colors.black45,
            //背景色
            backgroundColor: Colors.blue,
            ////触发下拉刷新的距离 默认40
            displacement: 40,
            //下拉回调方法,方法需要有async和await关键字,没有await,刷新图标立马消失,没有async,刷新图标不会消失
            onRefresh: refresh,
            child: ListView.separated(
              itemBuilder: ((context, index) {
                return getItem(index);
              }),
              separatorBuilder: (context, index) {
                return Divider(
                  color: Colors.black45,
                  height: 10,
                );
              },
              itemCount: getItemCount(),
              controller: _scrollController,
              //保持ListView任何情况都能滚动,解决在RefreshIndicator的兼容问题。
              physics: const AlwaysScrollableScrollPhysics(),
            ),
          ),
        );
      }
    }
    

    轮播图

    首先,用到的是PageView,以及PageController,这些之前已经说过,就不在细说

      Widget _pageView() {
        return PageView(
          children: <Widget>[
            Image.network(
              'http://img4.imgtn.bdimg.com/it/u=1621655683,865218969&fm=200&gp=0.jpg',
              height: 150,
              fit: BoxFit.fitWidth,
            ),
            Image.network(
              'http://img1.imgtn.bdimg.com/it/u=1901690610,3955011377&fm=200&gp=0.jpg',
              height: 150,
              fit: BoxFit.fitWidth,
            ),
            Image.network(
              'http://img3.imgtn.bdimg.com/it/u=1546158593,2358526642&fm=200&gp=0.jpg',
              height: 150,
              fit: BoxFit.fitWidth,
            ),
          ],
          controller: pageController,
        );
      }
    

    其次,需要一个定时器,别忘记取消

      int count = 3;
      int currentPosition = 0;
    
      @override
      void initState() {
        super.initState();
        _timer = new Timer.periodic(Duration(seconds: 2), (time) {
           //每2秒执行一次
          changePage();
        });
      }
    
      @override
      void dispose() {
        super.dispose();
        _timer.cancel();
        pageController.dispose();
      }
      void changePage() {
          pageController.animateToPage(currentPosition % count,
              duration: Duration(milliseconds: 200), curve: Curves.fastOutSlowIn);
        currentPosition++;
      }
    

    效果图如下


    20190625_175123.gif

    当我们手动滑动时,currentPosition会错乱,我们需要对其进行调整,需要用到的是onPageChanged属性

          onPageChanged: (index) {
            _timer.cancel();
            currentPosition = index;
            _timer = new Timer.periodic(Duration(seconds: 2), (time) {
              changePage();
            });
          },
    

    当然,这么常用的控件,已经有造好的轮子了 flutter_swiper
    首先添加依赖flutter_swiper: ^1.1.6
    下面是一些常用属性

      Widget _swiper() {
        return new Swiper(
          itemBuilder: (BuildContext context, int index) {
            return new Image.network(
              "http://img4.imgtn.bdimg.com/it/u=1621655683,865218969&fm=200&gp=0.jpg",
              fit: BoxFit.fitWidth,
              height: 150,
            );
          },
          itemCount: 3,
          //动画时间,默认300.0毫秒
          duration: 300,
          //初始位置
          index: 0,
          //无限轮播模式开关
          loop: true,
          //是否自动播放,默认false
          autoplay: true,
          layout: SwiperLayout.DEFAULT,
          //滚动方式
          scrollDirection: Axis.horizontal,
          //点击轮播的事件
          onTap: (index) {},
          //用户拖拽的时候,是否停止自动播放
          autoplayDisableOnInteraction: true,
          //指示器
          pagination: new SwiperPagination(),
          //左右箭头
          control: null,
        );
      }
    

    相关文章

      网友评论

        本文标题:【Flutter】开发之进阶Widget(五)

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