Flutter开发笔记 —— 绘制糖豆人动画

前言

今天在掘金上看到用Flutter绘制糖豆人动画的相关教程,心血来潮,简单看了一下思路,自己实现了一下

原文地址:https://juejin.cn/post/7088268036804706318

功能展示

实现逻辑

动画

  • 定义两个Animation Controller & Animation<double> 分别控制身体和球体的动画控制
  • 定义Listener用来更新状态

绘制

  • 定义两个颜色Color 分别为身体颜色 和 球体颜色
  • 定义画布,构造方法传递参数为身体Animation和球体Animation 以及两个相关颜色
  • 绘制身体 以及球和眼睛,传递相关动画Value 进行状态更新

实例

准备工作结束后,我们开始看看代码如何写

绘制

class AnimationPaint extends CustomPainter{
  //糖豆人身体颜色
  final Color bodyColor;
  //豆豆颜色
  final Color propColor;
  final Animation<double> bodyValue;
  final Animation<double> propColorValue;
  final Listenable listenable;
  final Size size;
  AnimationPaint(this.listenable, this.bodyColor, this.propColor, this.bodyValue, this.propColorValue, this.size) : super(repaint: listenable);

  @override
  void paint(Canvas canvas, Size size) {
    Rect rect = Rect.fromLTWH(0, 0, size.width, size.height);
    Paint paint = Paint()..color = Colors.red;
    canvas.saveLayer(rect, paint);
    drawBody(canvas, size);
    drawEye(canvas, size);
    drawLegumes(canvas, size);
    canvas.restore();
    // TODO: implement paint
  }

  drawBody(Canvas canvas,Size size){
    final paint = Paint()..color = bodyColor!..style = PaintingStyle.fill..strokeWidth = 2;
    var rect = Rect.fromCenter(
        center: Offset(size.width / 2, size.height / 2), width: 100, height: 100);
    // 结束角度;
    var a = bodyValue.value * 40 / 180 * pi;
    // 绘制圆弧
    canvas.drawArc(rect, a, 2 * pi - a * 2, true, paint);
  }

  /*
   * @author Marinda
   * @date 2023/12/29 16:30
   * @description 绘制眼睛 一黑一白
   */
  drawEye(Canvas canvas,Size size){
    //黑
    Offset eyeOffset = Offset((size.width / 2),(size.height / 2) -30);
    //白
    Offset eye2Offset = Offset((size.width / 2) -3,(size.height / 2) -35);
    Rect eyeRect = Rect.fromCenter(center: eyeOffset, width: 20, height: 20);
    Rect eyeRect2 = Rect.fromCenter(center: eye2Offset, width: 5, height: 5);
    final blackPaint = Paint()..color = Colors.black..strokeWidth = 2..style = PaintingStyle.fill;
    final whitePaint = Paint()..color = Colors.white..strokeWidth = 2..style = PaintingStyle.fill;
    canvas.drawOval(eyeRect,blackPaint);
    canvas.drawOval(eyeRect2,whitePaint);
  }


  /*
   * @author Marinda
   * @date 2023/12/29 16:05
   * @description 绘制豆
   */
  drawLegumes(Canvas canvas,Size size){
    Offset location = Offset((size.width / 2) + propColorValue.value,size.height /2);
    Rect rect = Rect.fromCenter(center: location, width: 15, height: 15);
    final paint = Paint()..color = propColor..strokeWidth = 2..style = PaintingStyle.fill;
    // canvas.drawCircle(location, radius, paint);
    canvas.drawOval(rect, paint);
  }


  @override
  bool shouldRepaint(covariant AnimationPaint oldDelegate) {
    return oldDelegate.listenable != listenable;
  }

}

State


class CustomState extends State<CustomAnimation2> with TickerProviderStateMixin{
  //圆弧角度
  late Animation<double> animation;
  //糖豆位置
  late Animation<double> animation2;
  Color? bodyColor;
  Color? propColor;
  late AnimationController controller;
  late AnimationController controller2;

  @override
  void initState() {
    controller = AnimationController(vsync: this,duration: Duration(milliseconds: 300),reverseDuration: Duration(milliseconds: 300));
    controller2 = AnimationController(vsync: this,duration: Duration(milliseconds: 500));
    animation = Tween<double>(begin: 0.2,end:1).animate(controller);
    animation2 = Tween<double>(begin: 50,end: 0).animate(controller2);
    controller.addStatusListener((status) {
      // print('动画状态: ${status}');
      if(status == AnimationStatus.completed){
        controller.reverse();

      }else if(status == AnimationStatus.dismissed){
        controller.forward();
        //已经执行完毕
        controller2.reset();
        controller2.forward();
        propColor = randomColor();
        setState(() {});
      }
    });
    controller2.addStatusListener((status) {
      if(status == AnimationStatus.completed){
        bodyColor = propColor;
        setState(() {});
      }
    });
    controller2.forward();
    controller.forward();
    // TODO: implement initState
    super.initState();
  }


  @override
  void dispose() {
    controller.dispose();
    controller2.dispose();
    super.dispose();
  }

  /*
   * @author Marinda
   * @date 2023/12/25 16:03
   * @description 随机颜色
   */
  Color randomColor(){
    Color? color;
    Random random = Random.secure();
    int ranRed = random.nextInt(255).round();
    int ranGreen = random.nextInt(255).round();
    int ranBlue = random.nextInt(255).round();
    color = Color.fromRGBO(ranRed,ranGreen,ranBlue,1);
    return color; 
  }

  @override
  Widget build(BuildContext context) {
    var size = MediaQuery.of(context).size;
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Colors.blue,
        title: Text("糖豆人动画",
          style: TextStyle(
              color: Colors.white,
              fontSize: 18
          )),
        centerTitle: true,
        leading: IconButton(
          icon: Icon(Icons.arrow_back_ios,size: 18,color: Colors.white,),
          onPressed: () {
            Navigator.pop(context);
          },
        ),
      ),
      body: Container(
        child: Stack(
          alignment: Alignment.center,
          children: [
            Container(
              child: CustomPaint(
                size: Size(size.width,size.height),
                painter: AnimationPaint(
                  Listenable.merge([animation,animation2]),
                  bodyColor ?? Colors.black,
                  propColor ?? Colors.black,
                  animation,
                  animation2,
                  Size(300,300)
               )
              )
            )
          ],
        ),
      ),
    );
  }

}

结束语

绘制其实很简单,无非就是传递控制动画结果以及相关弧形绘制,感谢你的观看!

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇