加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

Flutter仿掘金点赞效果

发布时间:2020-12-14 14:40:15 所属栏目:百科 来源:网络整理
导读:老孟导读:今天分享一下如何实现掘金点赞效果,这不仅仅是一篇技术文章,还是一篇解决问题思路的文章,遇到一个需求时,如何拆分需求,然后一步一步实现,这个过程比单纯的技术(此文)更有含金量。 先来看一下掘金点赞的效果: 说点题外话,感谢一下 二哥

老孟导读:今天分享一下如何实现掘金点赞效果,这不仅仅是一篇技术文章,还是一篇解决问题思路的文章,遇到一个需求时,如何拆分需求,然后一步一步实现,这个过程比单纯的技术(此文)更有含金量。

先来看一下掘金点赞的效果:

jue_1

说点题外话,感谢一下二哥沉默王二 ),给了我很多建议和帮助,公众号搜索沉默王二即可关注。

遇到组合动画效果时,首先拆分一下这个动画,以掘金点赞效果为例,共分为3个动画效果:

  1. 小手图标改变颜色并且缩放一下。
  2. 圆环由粗变细,透明度逐渐变为0。
  3. 最外圈小点点透明度逐渐变为0。

拆分好了之后,就一步一步实现其效果。

小手缩放效果

小手缩放效果需要2个图标,选中和未选中两种状态,我从阿里的图标库中选了2个类似的图标(未找到一摸一样的)。两种状态的图标定义如下:

///
/// 未点赞icon
///
const Icon _unLikeIcon = Icon(
  IconData(0xe60a,fontFamily: 'appIconFonts'),);

///
/// 点赞icon
///
const Icon _likeIcon = Icon(
  IconData(0xe60c,color: Color(0xFF1afa29),);

关于如何使用阿里的图标库中的图标可以查看此文章。

由于小手图标的动画效果是放大->还原,使用组合动画实现其效果,代码如下:

@override
initState() {
  _animationController =
      AnimationController(duration: Duration(milliseconds: 300),vsync: this);


  _iconAnimation = Tween(begin: 1.0,end: 1.3).animate(_animationController);

  _iconAnimation = TweenSequence([
    TweenSequenceItem(
        tween: Tween(begin: 1.0,end: 1.3)
            .chain(CurveTween(curve: Curves.easeIn)),weight: 50),TweenSequenceItem(tween: Tween(begin: 1.3,end: 1.0),]).animate(_animationController);
}

@override
  Widget build(BuildContext context) {
    return _buildLikeIcon();
  }

_buildLikeIcon() {
    return ScaleTransition(
      scale: _iconAnimation,child: widget.like
          ? IconButton(
              padding: EdgeInsets.all(0),icon: _likeIcon,onPressed: () {
                _clickIcon();
              },)
          : IconButton(
              padding: EdgeInsets.all(0),icon: _unLikeIcon,),);
  }

添加按钮点击效果:

_clickIcon() {
  if (_iconAnimation.status == AnimationStatus.forward ||
      _iconAnimation.status == AnimationStatus.reverse) {
    return;
  }
  setState(() {
    widget.like = !widget.like;
  });
  if (_iconAnimation.status == AnimationStatus.dismissed) {
    _animationController.forward();
  } else if (_iconAnimation.status == AnimationStatus.completed) {
    _animationController.reverse();
  }
}

jue_2

圆环动画

圆环的动画效果是线条宽度逐渐变为0,透明度逐渐变为0,相对简单,使用AnimatedBuilder实现:

_buildCircle() {
  return !widget.like
      ? Container()
      : AnimatedBuilder(
          animation: _circleAnimation,builder: (BuildContext context,Widget child) {
            return Container(
              decoration: BoxDecoration(
                  shape: BoxShape.circle,border: Border.all(
                      color: Color(0xFF5FA0EC)
                          .withOpacity(_circleAnimation.value),width: _circleAnimation.value * 8)),);
          },);
}

定义_circleAnimation

_circleAnimation =
    Tween(begin: 1.0,end: 0.0).animate(_animationController);

jue_3

最外圈小点点

最外圈的小点点动画效果是最简单的,透明度逐渐变为0,但布局相对复杂,围绕小手形成一个圆形,使用Flow实现此布局,Flow是一个非常酷炫的布局组件,更多用法查看此文。

构建单个小圆点

_buildCirclePoint(double radius,Color color) {
  return !widget.like
      ? Container()
      : AnimatedBuilder(
          animation: _circleAnimation,Widget child) {
            return Container(
              width: radius,height: radius,decoration: BoxDecoration(
                  shape: BoxShape.circle,color: color.withOpacity(_circleAnimation.value)),);
}

构建围绕小手的多个点:

_buildCirclePoints() {
  return Flow(
    delegate: CirclePointFlowDelegate(),children: <Widget>[
      _buildCirclePoint(2,Color(0xFF97B1CE)),_buildCirclePoint(5,Color(0xFF4AC6B7)),_buildCirclePoint(2,],);
}

CirclePointFlowDelegate 定义如下:

class CirclePointFlowDelegate extends FlowDelegate {
  CirclePointFlowDelegate();

  @override
  void paintChildren(FlowPaintingContext context) {
    var radius = min(context.size.width,context.size.height) / 2.0;
    //中心点
    double rx = radius;
    double ry = radius;
    for (int i = 0; i < context.childCount; i++) {
      if (i % 2 == 0) {
        double x =
            rx + (radius - 5) * cos(i * 2 * pi / (context.childCount - 1));
        double y =
            ry + (radius - 5) * sin(i * 2 * pi / (context.childCount - 1));
        context.paintChild(i,transform: Matrix4.translationValues(x,y,0));
      } else {
        double x = rx +
            (radius - 5) *
                cos((i - 1) * 2 * pi / (context.childCount - 1) +
                    2 * pi / ((context.childCount - 1) * 3));
        double y = ry +
            (radius - 5) *
                sin((i - 1) * 2 * pi / (context.childCount - 1) +
                    2 * pi / ((context.childCount - 1) * 3));
        context.paintChild(i,0));
      }
    }
  }

  @override
  bool shouldRepaint(FlowDelegate oldDelegate) => true;
}

jue_4

交流

老孟Flutter博客地址(近200个控件用法):http://laomengit.com

欢迎加入Flutter交流群(微信:laomengit)、关注公众号【老孟Flutter】:

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读