最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • Flutter-实现简洁好看的PageView指示器

    正文概述 掘金(rhyme_lph)   2021-02-18   455

    1.介绍

    在使用PageView时,我们通常需要添加指示器,以避免用户产生只有一张图片显示的错觉,所以,添加指示器是必不可少的!但是,有时候图片一多,指示器也同样的出现多的情况,导致显示的指示器不能显示太大,并且间距也需要适当的减少,下面来看一下我实现的效果,简洁大方!

    Flutter-实现简洁好看的PageView指示器

    2.开始实现

    首先,我们要确定传进来的参数有哪些

    • PageController controller 用于绑定指示器
    • int itemCount 与PageView对应,需要确认有多少页
    • Color indicatorColor 指示器的颜色
    • double maxSize 指示器到达中间时的大小
    • double minSize 指示器两边圆点的大小
    • double space 指示器两圆点之间的间距

    确认上面的参数后,我们来新建一个dart文件,命名为simple_page_indicator.dart ,然后添加下面的内容

    class SimplePageIndicator extends StatelessWidget {
      final PageController controller;
      final int itemCount;
      final Color indicatorColor;
      final double maxSize;
      final double minSize;
      final double space;
    
      const SimplePageIndicator(
          {Key key,
          this.controller,
          this.itemCount,
          this.indicatorColor,
          this.maxSize,
          this.space,
          this.minSize})
          : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        return Container();
      }
    }
    

    接下来,我们需要使用AnimatedBuilder,并传入animation参数为controller

    //...
      @override
      Widget build(BuildContext context) {
    //    return Container();
        return AnimatedBuilder(animation: controller, builder: _buildAnimatedItem);
      }
    
      Widget _buildAnimatedItem(BuildContext context, Widget child) {
        return Container();
      }
    //...
    

    这样我们就能监听到PageController的值发生改变时做出指示器对应的变化,下面我们来使用CustomPaint 对指示器进行绘制,新加一个SimplePageIndicatorPainter类并将对应的值传递过去继续修改

    //...
      Widget _buildAnimatedItem(BuildContext context, Widget child) {
        // return Container();
        return CustomPaint(
          painter: SimplePageIndicatorPainter(
            itemCount: itemCount,
            indicatorColor: indicatorColor,
            maxSize: maxSize,
            minSize: minSize,
            space: space,
            pageIndex: 0,
            pageOffset: .0
          ),
        );
      }
    /// ...
    
    class SimplePageIndicatorPainter extends CustomPainter {
      final int itemCount;
      final Color indicatorColor;
      final double maxSize;
      final double minSize;
      final int pageIndex;
      final double pageOffset;
      final double space;
    
      const SimplePageIndicatorPainter(
          {this.itemCount,
          this.indicatorColor,
          this.maxSize,
          this.space,
          this.minSize,
          this.pageIndex,
          this.pageOffset});
    
      @override
      void paint(Canvas canvas, Size size) {}
    
      @override
      bool shouldRepaint(covariant SimplePageIndicatorPainter oldDelegate) {
        return true;
      }
    }
    
    

    下面,我们来开始画对应的小圆点,我们默认的将指示器的位置设置为0起点和偏移量也为0,我们需要画三个点,因为当前是在0起始位,我们只需要画两个点,一个大的点在中间,另一个小点在最右边

    // ...
    const _kMaxCircleCount = 3; // 默认三个圆点
    
    class SimplePageIndicatorPainter extends CustomPainter {
      final int itemCount;
      final Color indicatorColor;
      final double maxSize;
      final double minSize;
      final int pageIndex;
      final double pageOffset;
      final double space;
      final bool isStart;
      final bool isEnd;
    
      const SimplePageIndicatorPainter(
          {this.itemCount,
          this.indicatorColor,
          this.maxSize,
          this.space,
          this.minSize,
          this.pageIndex,
          this.pageOffset,
          this.isStart,
          this.isEnd});
    
      @override
      void paint(Canvas canvas, Size size) {
        //初始化画笔
        Paint mPaint = Paint()
          ..color = indicatorColor
          ..isAntiAlias = true;
    
        //获取中间的圆点为第几个
        final _centerCircleIndex = _kMaxCircleCount ~/ 2;
        //获取每个圆点占据的大小,把widget分为3份
        double childWidth = size.width / _kMaxCircleCount;
    
        //遍历画圆点
        for (int i = 0; i < _kMaxCircleCount; i++) {
          // 当页数为0的时候,也就是第一页,不画第一个圆点
          if (pageIndex == 0 && i == 0) {
            continue;
          }
          if (isEnd && i == _kMaxCircleCount - 1) {
            continue;
          }
          //画中心圆
          if (_centerCircleIndex == i) {
            canvas.drawCircle(
                Offset(
                    (i * childWidth) + (childWidth / 2) - childWidth * pageOffset,
                    childWidth / 2),
                maxSize - (maxSize - minSize) * pageOffset,
                mPaint..color = indicatorColor);
          }
          //画左边的圆
          else if (i < _centerCircleIndex) {
            canvas.drawCircle(
                Offset(
                    (i * childWidth) + (childWidth / 2) - childWidth * pageOffset,
                    childWidth / 2),
                minSize * (1 - pageOffset),
                mPaint..color = indicatorColor.withOpacity(1 - pageOffset));
          }
          //话右边的圆
          else {
            canvas.drawCircle(
                Offset(
                    (i * childWidth) + (childWidth / 2) - childWidth * pageOffset,
                    childWidth / 2),
                minSize + (maxSize - minSize) * pageOffset,
                mPaint..color = indicatorColor);
          }
        }
        //向左移的时候画后面的圆
        if (isStart && !isEnd) {
          canvas.drawCircle(
              Offset(
                  (_kMaxCircleCount * childWidth) +
                      (childWidth / 2) -
                      childWidth * (pageOffset),
                  childWidth / 2),
              minSize * pageOffset,
              mPaint..color = indicatorColor.withOpacity(pageOffset));
        }
      }
    
      @override
      bool shouldRepaint(covariant SimplePageIndicatorPainter oldDelegate) {
        return itemCount != oldDelegate.itemCount ||
            indicatorColor != oldDelegate.indicatorColor ||
            maxSize != oldDelegate.maxSize ||
            minSize != oldDelegate.minSize ||
            space != oldDelegate.space ||
            pageIndex != oldDelegate.pageIndex ||
            isStart != oldDelegate.isStart ||
            isEnd != oldDelegate.isEnd;
      }
    }
    // ...
    

    最后我们来处理一下 pageController传过来的值即可

    Widget _buildAnimatedItem(BuildContext context, Widget child) {
       // return Container();
       //当前页数
       int index;
       //偏移量
       double offset;
    
       //如果获取不了,则使用初始化的值,一般第一次渲染的时候无法获取到
       if (!controller.hasClients || controller.page == null) {
         index = controller.initialPage;
         offset = controller.initialPage.toDouble();
       } else {
         index = controller.page ~/ 1;
         offset = controller.page;
       }
    
       return CustomPaint(
         size: Size(
             maxSize * _kMaxCircleCount + space * (_kMaxCircleCount - 1), maxSize),
         painter: SimplePageIndicatorPainter(
             itemCount: itemCount,
             indicatorColor: indicatorColor,
             maxSize: maxSize,
             minSize: minSize,
             pageIndex: index,
             space: space,
             pageOffset: offset - index,
             isStart:
                 (offset > index) && (index + _kMaxCircleCount - 1 < itemCount),
             isEnd: index + _kMaxCircleCount - 2 >= itemCount),
       );
     }
    

    详细代码请查看:这里

    直接使用:

    dependencies:
      simple_page_indicator: ^1.0.0
    

    起源地下载网 » Flutter-实现简洁好看的PageView指示器

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元