用Flutter实现一个仿Twitter的点赞效果

2019.05.30更新:
  法海大佬在个人基础上对点赞控件作了优化和封装,API调用更加方便了。你们能够看我这篇文章了解下绘制思路,实际使用推荐使用法海大佬的,用起来更方便:Flutter 仿掘金推特色赞按钮
git

  此次依然是补做业,以前在写仿“探探”左滑/右滑的效果的时候,设计稿底部的喜欢Icon实际上是有相似于Twitter点赞那种的动效的,可是由于时间缘由我偷懒没写。
  惯例先上效果图:github

  GitHub地址:github.com/yumi0629/Fl…算法

  总体算法是参照了GitHub上star最多的jd-alexander大佬写的LikeButton,我进行了调整,并最终用Flutter实现。
  一点小缺陷:如今的实现方式,icon大小无法自适应,须要初始化布局的时候手动传入一个size。canvas

设计思路

  咱们将动画放慢,很明显总体动画由三部分组成:中间Icon的放大、底部圆环的交替和外部烟花散开的效果: bash

总体布局

  由于是层叠布局,咱们依旧是使用Stack来实现,底部圆环的交替和外部烟花散开的效果是使用的CustomPaint来绘制,而中间的小图标则是使用的普通Widget实现:ide

Stack(
      alignment: Alignment.center,
      children: <Widget>[
        CustomPaint(
          size: Size(widget.width, widget.width),
          painter: DotPainter(),
        ),
        CustomPaint(
          isComplex: true,
          size: Size(widget.width * 0.35, widget.width * 0.35),
          painter: CirclePainter(),
        Container(
          width: widget.width,
          height: widget.width,
          alignment: Alignment.center,
          child: Transform.scale(
            scale: isLiked ? scale.value : 1.0,
            child: GestureDetector(
              child: Icon(),
              onTap: _onTap,
            ),
          ),
        ),
      ],
    );
复制代码

  Paint的绘制在这里就很少说了,由于基本都是数学问题。总体效果的实现主要是要学会用一个Controller来控制多个动画。布局

动画控制 Staggered Animation

  这一期主要是想跟你们讲讲如何用一个Controller来控制多个动画同时进行,也就是Flutter中的Staggered Animation(交错动画)。
  咱们能够定义不少个Animation,将他们和同一个controller绑定:post

Animation<double> outerCircle = new Tween<double>(
      begin: 0.1,
      end: 1.0,
    ).animate(
      new CurvedAnimation(
        parent: _controller,
        curve: new Interval(
          0.0,
          0.3,
          curve: Curves.ease,
        ),
      ),
    );
    Animation<double> innerCircle = new Tween<double>(
      begin: 0.2,
      end: 1.0,
    ).animate(
      new CurvedAnimation(
        parent: _controller,
        curve: new Interval(
          0.2,
          0.5,
          curve: Curves.ease,
        ),
      ),
    );Animation<double> 

复制代码

  上面的例子中,outerCircleinnerCircle共享同一个_controller,而各自的播放顺序经过Interval来控制:outerCircle的动画时间为总体进度的0.0~0.3,innerCircle的动画时间为总体进度的0.2~0.5。对于单个动画的进度,咱们能够经过outerCircle.valueinnerCircle.value来获取,单个动画的进度范围依然是0.0~1.0,因此绘制每一组动画时,不须要去手动转换。优化

绘制中的一些坑

  此次碰到的主要问题是paintblendMode属性有坑,由于底部两个圆环在绘制时的思路是:大圆环绘制到一半时,开始绘制小圆环将其遮盖住,可是小圆环的颜色咱们无法设定,由于咱们不知道画布是什么颜色的,所以无法用相同的颜色去遮盖住大圆环。这个问题能够经过设置paintblendMode属性为BlendMode.clear解决,看名字就很好理解,就是清除以前的绘制区域,可是这个BlendMode.clear有bug。
  若是你直接像下面这样写,那么你会发现,clear掉的部分会变成黑色:动画

circlePaint..style = PaintingStyle.fill;
maskPaint..blendMode = BlendMode.clear;

  @override
  void paint(Canvas canvas, Size size) {
    canvas.drawCircle(Offset(center, center), 20.0, circlePaint);
    canvas.drawCircle(Offset(center, center), 10.0, maskPaint);
  }
复制代码

  解决方法就是在绘制前保存一下当前layer:

canvas.saveLayer(Offset.zero & size, Paint());
canvas.drawCircle(Offset(center, center), 20.0, circlePaint);
canvas.drawCircle(Offset(center, center), 10.0, maskPaint);
canvas.restore();
复制代码
相关文章
相关标签/搜索