欢迎访问移动开发之家(rcyd.net),关注移动开发教程。移动开发之家  移动开发问答|  每日更新
页面位置 : > > > 内容正文

基于Flutter制作一个心碎动画特效,

来源: 开发者 投稿于  被查看 22004 次 评论:7

基于Flutter制作一个心碎动画特效,


目录
  • 前言
  • 实现步骤
    • 1、绘制一个心
    • 2、绘制心的裂痕
    • 3、加入动画
  • 完整代码
    • 小结

      前言

      继续动画探索,今天用Flutter制作一个心碎的感觉,灵感来源于今天的股市,哎,心哇凉哇凉的。废话不多说,开始。

      效果图先上:

      实现步骤

      1、绘制一个心

      首先我们使用两段三阶贝塞尔曲线制作一个心型,这里因为需要实现心碎的效果,所以我们需要将心的两段用两段路径path进行绘制出来,效果:

      绘制代码:

      canvas.translate(size.width / 2, size.height / 2);
      Paint paint = Paint();
      paint
        ..style = PaintingStyle.stroke
        ..strokeWidth = 2
        ..color = Colors.black87;
      Path path = Path();
      path.moveTo(0, 0);
      path.cubicTo(-200, -80, -60, -240, 0, -140);
      path.close();
      Path path2 = Path();
      canvas.save();
      canvas.drawPath(
          path,
          paint
          ..color = Colors.red
            ..style = PaintingStyle.stroke);
      canvas.restore();
      path2.cubicTo(200, -80, 60, -240, 0, -140);
      path2.close();
      canvas.drawPath(
          path2,
          paint..color = Colors.black87);

      2、绘制心的裂痕

      我们看到心确实分成两半了,但是中间还缺少裂痕,接下来我们就绘制心碎的裂痕,也很简单,在两段路径path闭合前进行绘制线,效果:

      绘制代码:

      path.relativeLineTo(-10, 30);
      path.relativeLineTo(20, 5);
      path.relativeLineTo(-20, 30);
      path.relativeLineTo(20, 20);
      path.relativeLineTo(-10, 20);
      path.relativeLineTo(10, 10);
      
      path2.relativeLineTo(-10, 30);
      path2.relativeLineTo(20, 5);
      path2.relativeLineTo(-20, 30);
      path2.relativeLineTo(20, 20);
      path2.relativeLineTo(-10, 20);
      path2.relativeLineTo(10, 10);

      OK,我们已经看到心已经有了裂痕,如何心碎,只需将画布进行翻转一定角度即可,这里我们将画布翻转45°,看下效果:

      左边:

      右边:

      3、加入动画

      已经有心碎的感觉了,接下来加入动画元素让心碎的过程动起来。

      思路: 我们可以想一下,心碎的过程是什么样子,心的颜色慢慢变灰,心然后慢慢裂开,下方的动画运动曲线看起来更符合心碎的过程,里面有不舍,不甘,但最后心还是慢慢的碎了。

      我们把画笔进行填充将这个动画加入进来看下最终效果。

      是不是心碎了一地。

      知识点: 这里我们需要找到红色和灰色的RGB色值,通过Color.fromRGBO(r, g, b, opacity)方法赋值颜色的色值。然后通过动画值改变RGB的值即可。 这里我使用的色值是:

      红色:Color.fromRGBO(255, 0, 0, 1)灰色:Color.fromRGBO(169, 169, 169, 1)

      完整代码

      class XinSui extends StatefulWidget {
        const XinSui({Key? key}) : super(key: key);
      
        @override
        _XinSuiState createState() => _XinSuiState();
      }
      
      class _XinSuiState extends State<XinSui> with SingleTickerProviderStateMixin {
        late AnimationController _controller =
            AnimationController(vsync: this, duration: Duration(milliseconds: 4000))
              ..repeat();
        late CurvedAnimation cure =
            CurvedAnimation(parent: _controller, curve: Curves.bounceInOut);
      
        late Animation<double> animation =
            Tween<double>(begin: 0.0, end: 1.0).animate(cure);
      
        @override
        Widget build(BuildContext context) {
          return Container(
            child: CustomPaint(
              size: Size(double.infinity, double.infinity),
              painter: _XinSuiPainter(animation),
            ),
          );
        }
      
        @override
        void dispose() {
          _controller.dispose();
          super.dispose();
        }
      }
      
      class _XinSuiPainter extends CustomPainter {
        Animation<double> animation;
      
        _XinSuiPainter(this.animation) : super(repaint: animation);
      
        @override
        void paint(Canvas canvas, Size size) {
          canvas.translate(size.width / 2, size.height / 2);
          Paint paint = Paint();
          paint
            ..style = PaintingStyle.stroke
            ..strokeWidth = 2
            ..color = Colors.black87;
          Path path = Path();
          path.moveTo(0, 0);
          path.cubicTo(-200, -80, -60, -240, 0, -140);
          path.relativeLineTo(-10, 30);
          path.relativeLineTo(20, 5);
          path.relativeLineTo(-20, 30);
          path.relativeLineTo(20, 20);
          path.relativeLineTo(-10, 20);
          path.relativeLineTo(10, 10);
          path.close();
          Path path2 = Path();
          canvas.save();
          canvas.rotate(-pi / 4 * animation.value);
          canvas.drawPath(
              path,
              paint
              ..color = Colors.red
                ..color = Color.fromRGBO(
                    255 - (86 * animation.value).toInt(),
                    (animation.value * 169).toInt(),
                    (animation.value * 169).toInt(),
                    1)
      
                ..style = PaintingStyle.fill);
          canvas.restore();
          path2.cubicTo(200, -80, 60, -240, 0, -140);
          path2.relativeLineTo(-10, 30);
          path2.relativeLineTo(20, 5);
          path2.relativeLineTo(-20, 30);
          path2.relativeLineTo(20, 20);
          path2.relativeLineTo(-10, 20);
          path2.relativeLineTo(10, 10);
          path2.close();
          canvas.rotate(pi / 4 * animation.value);
          canvas.drawPath(
              path2,paint);
        }
        @override
        bool shouldRepaint(covariant _XinSuiPainter oldDelegate) {
          return oldDelegate.animation != animation;
        }
      }

      小结

      动画曲线Curves配合绘制可以实现很多好玩的东西,这个需要勤加练习方能掌握,仅将此心碎献给今天受伤的股民朋友们

      到此这篇关于基于Flutter制作一个心碎动画特效的文章就介绍到这了,更多相关Flutter心碎动画内容请搜索3672js教程以前的文章或继续浏览下面的相关文章希望大家以后多多支持3672js教程!

      您可能感兴趣的文章:
      • Flutter实现牛顿摆动画效果的示例代码
      • 基于Flutter制作一个吃豆人加载动画
      • Flutter实现心动的动画特效
      • Android Flutter实现五种酷炫文字动画效果详解
      • 基于Flutter实现爱心三连动画效果
      • Android Flutter实现3D动画效果示例详解

      用户评论