Flutter仿掘金点赞效果

05/20 07:30
阅读数 51


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


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


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


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

  1. 小手图标改变颜色并且缩放一下。

  2. 圆环由粗变细,透明度逐渐变为0。

  3. 最外圈小点点透明度逐渐变为0。

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


小手缩放效果

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

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

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

    http://laomengit.com/flutter/articles/openProject/iconfont.html


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

@overrideinitState() {  _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), weight: 50), ]).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, onPressed: () { _clickIcon(); }, ), ); }


添加按钮点击效果:

_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();  }}


圆环动画

圆环的动画效果是线条宽度逐渐变为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);


最外圈小点点

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

构建单个小圆点

_buildCirclePoint(double radius, Color color) {  return !widget.like      ? Container()      : AnimatedBuilder(          animation: _circleAnimation,          builder: (BuildContext context, 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, Color(0xFF97B1CE)),      _buildCirclePoint(5, Color(0xFF4AC6B7)),      _buildCirclePoint(2, Color(0xFF97B1CE)),      _buildCirclePoint(5, Color(0xFF4AC6B7)),      _buildCirclePoint(2, Color(0xFF97B1CE)),      _buildCirclePoint(5, Color(0xFF4AC6B7)),      _buildCirclePoint(2, Color(0xFF97B1CE)),      _buildCirclePoint(5, Color(0xFF4AC6B7)),      _buildCirclePoint(2, Color(0xFF97B1CE)),      _buildCirclePoint(5, Color(0xFF4AC6B7)),      _buildCirclePoint(2, Color(0xFF97B1CE)),      _buildCirclePoint(5, Color(0xFF4AC6B7)),      _buildCirclePoint(2, Color(0xFF97B1CE)),      _buildCirclePoint(5, Color(0xFF4AC6B7)),    ],  );}

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, transform: Matrix4.translationValues(x, y, 0)); } } }
@override bool shouldRepaint(FlowDelegate oldDelegate) => true;}


OK,效果到此完成了,将上面的代码组合在一起即可运行,如果您觉得麻烦也可以私信我获取完整代码:


你可能还喜欢


关注「老孟Flutter」
让你每天进步一点点

戳我,赠送250+Flutter控件详细说明。

本文分享自微信公众号 - 老孟Flutter(lao_meng_qd)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

展开阅读全文
打赏
0
0 收藏
分享
加载中
更多评论
打赏
0 评论
0 收藏
0
分享
在线直播报名
返回顶部
顶部