Flutter 的自定义 UI 系列(六)-示例:写轮眼动效
前言
CustomPainter 除了常规的绘制外,还可以配合 AnimationController
实现动态效果。这篇文章将展示一个写轮眼的绘制动画。具体效果看封面,没有太多的技术难点,就是计算点位置和调用对应的 API 做绘制。
步骤一 背景的绘制
绘制背景,比较简单,绘制两个圆就可以了。
技巧:绘制圆形相关的图像时,可以把画布的原点挪到 widget 的中心,这样在计算三角函数、旋转画布等操作更方便。
@override void paint(Canvas canvas, Size size) { var center = size.center(Offset.zero); // 挪到画布到 CustomPaint 的中心位置 canvas.translate(center.dx, center.dy); canvas.save(); canvas.restore(); } 复制代码
步骤二 三勾玉的绘制
计算并找到点的位置,用圆和一个path路径共同绘制了一个勾玉。
void _drawMagatama(Offset center, Canvas canvas) { var magatamaOrigin = center.translate(90, 0); canvas.drawCircle(magatamaOrigin, 20, blackPaintFill); path.moveTo(magatamaOrigin.dx, magatamaOrigin.dy); path.relativeLineTo(0, -20); var magatamaEnd = magatamaOrigin.translate(40, 20); path.conicTo(magatamaOrigin.dx + 20, magatamaOrigin.dy - 20, magatamaEnd.dx, magatamaEnd.dy, 1); path.moveTo(magatamaOrigin.dx, magatamaOrigin.dy); path.conicTo(magatamaOrigin.dx + 20, magatamaOrigin.dy - 10, magatamaEnd.dx, magatamaEnd.dy, 1); path.close(); canvas.drawPath(path, blackPaintFill); } 复制代码
另外两个勾玉可以旋转画布,调用同一个绘制方法。省去了计算点位置的步骤。
canvas.save(); canvas.rotate(pi * 2 / 3); canvas.rotate(_animationDirection); _drawMagatama(Offset.zero, canvas); canvas.restore(); canvas.save(); canvas.rotate(pi * 4 / 3); canvas.rotate(_animationDirection); _drawMagatama(Offset.zero, canvas); canvas.restore(); 复制代码
步骤三 万花筒绘制
万花筒的边缘是个贝塞尔曲线,找到对应的点绘制曲线就可以了
Offset ctrPoint1 = Offset(-30, -100); Offset ctrPoint2 = Offset(90, 150); Path path = Path(); var offsetA = Offset(145, 0); var offsetB = Offset(radius * cos(pi * 2 / 3), radius * sin(pi * 2 / 3)); path.moveTo(offsetA.dx, offsetA.dy); path.cubicTo(ctrPoint1.dx, ctrPoint1.dy, ctrPoint2.dx, ctrPoint2.dy, offsetB.dx, offsetB.dy); canvas.drawPath(path, blackPaint..strokeWidth=1); 复制代码
绘制另外两条曲线时,用到了三角函数,这也是 canvas 绘制中最常用的函数,用来计算指定角度点的位置的方法。
var offsetB = Offset(radius * cos(pi * 2 / 3), radius * sin(pi * 2 / 3)); var offsetC = Offset(radius * cos(pi * 4 / 3), radius * sin(pi * 4 / 3)); 复制代码
步骤四 加动效
创建 AnimationController
,并添加 CurvedAnimation
差值器,使动画效果更加逼真。关于差值器效果可以参考官方的示例 Curves
_controllerMagatama = AnimationController(vsync: this, duration: Duration(seconds: 6)); _curvedAnimationMagatama = CurvedAnimation(parent: _controllerMagatama, curve: Curves.elasticIn); _curvedAnimationMagatama.addListener(() { _valueMagatama = _curvedAnimationMagatama.value * 3; setState(() {}); }); _controllerMagatama.forward(); 复制代码
把 CurvedAnimation
的值传给 CustomPainter
再根据动画的值旋转画布对应的角度即可。最后就实现了封面的效果。
作者:码农王真实
链接:https://juejin.cn/post/7025518289887428621