Flutter 轮子之下雪动画(2)

Flutter 轮子之下雪动画,底部也有Android的下雪动画,记得点赞哦~

  • 画圆
  • 创建200个随机圆并绘制
  • 设置动画

还是老套路,先来看看今天要完成的效果:
Flutter 轮子之下雪动画(2)_第1张图片
首页的二维码是我的公众号,随后我会上传到公众号上

今天要完成的是最后的下雪动画~

先来分析一波:

  • 随机大小的雪花(圆)
  • 可以使雪花(圆)左右偏移
  • 雪花(圆)向右下角方向垂直移动
  • 雪花(圆)当消失之后会重复创建执行

画圆

先给大家介绍怎么画一个圆


 @override
  Widget build(BuildContext context) {
     
    return Container(
      color: Colors.black,
      child: CustomPaint(
        painter: MyCustomPainter(),
        //占满屏幕
        size: MediaQuery.of(context).size,
      ),
    );
  }


class MyCustomPainter extends CustomPainter {
     
//创建画笔
  Paint _paint = new Paint()
    ..isAntiAlias = true
    ..color = Colors.white;

  @override
  void paint(Canvas canvas, Size size) {
     
    canvas.drawCircle(Offset(100,100), 50, _paint);
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) {
     
  //刷新
    return true;
  }
}

可以参考文档Flutter 轮子之气泡登录页来了解这部分代码

效果图(1.1):
Flutter 轮子之下雪动画(2)_第2张图片
吧他写成类的形式:

创建雪花Bean类

class SnowBean {
     
  //位置
  Offset postion = Offset(100,100);

  //半径
  double radius = 50;
}


class MyCustomPainter extends CustomPainter {
     
  //创建画笔
   Paint _paint = new Paint()
    ..isAntiAlias = true
    ..color = Colors.white;
  @override
  void paint(Canvas canvas, Size size) {
     
   SnowBean snowBean = new SnowBean();
    canvas.drawCircle(snowBean.postion, snowBean.radius, _paint);
  }
  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) {
      .... }
}

效果图(1.2):
Flutter 轮子之下雪动画(2)_第3张图片
这部分代码很简单,就不说了.

创建200个随机圆并绘制

List<SnowBean> _list = [];

  @override
  void initState() {
     
    // TODO: implement initState
    super.initState();
    Future.delayed(Duration(seconds: 0), () {
     
      initData();
    });
  }

  void initData() {
     
    for (int i = 0; i <= 200; i++) {
     
      SnowBean snowBean = new SnowBean();
	//MediaQuery.of(context).size.width是屏幕的宽
	//MediaQuery.of(context).size.height是屏幕的高
      double dx = _random.nextDouble() * MediaQuery.of(context).size.width;
      double dy = _random.nextDouble() * MediaQuery.of(context).size.height;
       snowBean.postion = Offset(dx, dy);
      snowBean.radius = _random.nextDouble() + 1;
      _list.add(snowBean);
    }
  }


class MyCustomPainter extends CustomPainter {
     
  //创建画笔
  .....
    List<SnowBean> list;

  MyCustomPainter(this.list);
  @override
  void paint(Canvas canvas, Size size) {
     
    list.forEach((element) {
     
      canvas.drawCircle(element.postion, element.radius, _paint);
    });
  }
  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) {
      .... }
}

这段代码非常简单,就是在initState()初始化的时候,使用异步创建200个随机大小,随机位置的圆,并吧这个list传递给MyCustomPainter(),然他绘制出每一个圆

来看看效果吧:
Flutter 轮子之下雪动画(2)_第4张图片
现在是不是就很有感觉了~

设置动画

AnimationController _animationController;

  @override
  void initState() {
     
    // TODO: implement initState
    super.initState();
    //创建动画,执行为1秒
    _animationController =
        new AnimationController(vsync: this, duration: Duration(seconds: 10));

    //动画监听器
    _animationController.addListener(() {
     
      setState(() {
     });
    });

    //重复执行气泡动画
    _animationController.repeat();
  }

这段代码参考Flutter AnimatedWidget,AnimatedBuilder动画(2.4)

接下来重新写一下MyCustomPainter ()方法

class MyCustomPainter extends CustomPainter {
     
  List<SnowBean> list;
  Random _random;

  MyCustomPainter(this.list, this._random);

  Paint _paint = new Paint()
    ..isAntiAlias = true
    ..color = Colors.white;

  @override
  void paint(Canvas canvas, Size size) {
     

    list.forEach((element) {
     
      double dy = element.postion.dy;
      double dx = element.postion.dx;

      /**
       * 若Y轴雪花移动到屏幕以外,则让它回到起始位置
       */
      if (dy >= size.height) {
     
        dy = 0;
      }
      /**
       * 若X轴雪花移动到屏幕以外,则让它回到起始位置
       */
      if (dx >= size.width) {
     
        dx = 0;
      }

      element.postion =
          Offset(dx + _random.nextDouble(), dy + _random.nextDouble() + element.speed + 3);
    });

    list.forEach((element) {
     
      canvas.drawCircle(element.postion, element.radius, _paint);
    });
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) {
     
    return true;
  }
}

SnowBean添加移动的速度:
class SnowBean {
     
  //位置
  Offset postion = Offset(100, 100);

  //半径
  double radius = 50;

  //移动速度
  double speed;
}

重新初始化:
 void initData() {
     
    for (int i = 0; i <= 200; i++) {
     
      SnowBean snowBean = new SnowBean();

	  //_random.nextDouble()是0-1随机的小数
      double dx = _random.nextDouble() * MediaQuery.of(context).size.width;
      double dy = _random.nextDouble() * MediaQuery.of(context).size.height;
      snowBean.postion = Offset(dx, dy);
      snowBean.radius = _random.nextDouble() + 1;
      snowBean.speed = _random.nextDouble() + 5;

      _list.add(snowBean);
    }
  }


这段代码我相信大家看到大部分还是可以看懂的;

给大家解释一下这段代码:

  /**
       * 若Y轴雪花移动到屏幕以外,则让它回到起始位置
       */
      if (dy >= size.height) {
     
        dy = 0;
      }
      /**
       * 若X轴雪花移动到屏幕以外,则让它回到起始位置
       */
      if (dx >= size.width) {
     
        dx = 0;
      }

这段代码的意思是,当dx或者dy移动出屏幕时,让他重新绘制

 element.postion =
         Offset(dx + _random.nextDouble(),
          dy +  element.speed );
  • 参数一:dx 加 _random.nextDouble() 代表的是当前的经度加上一个0-1的随机数,有一个左右偏移的动画效果
  • 参数二:dy加一个下降的运行速度为当前的dy的值

来看看效果:
Flutter 轮子之下雪动画(2)_第5张图片
可能有同学还是会疑惑,让动画重复执行了,可是为什么雪花会动呢?

注意看这个setState(){}方法
Flutter 轮子之下雪动画(2)_第6张图片
其实啊:这里的setState(){}这个方法,一直在执行sholdRepaint方法()
Flutter 轮子之下雪动画(2)_第7张图片
先会判断这里的返回值,如果是true则会一直刷新paint()方法,paint()中的操作简单理解就是让dx左右移动,dy一直向下移动,当移动到屏幕外时,则让它回到起始位置,则达到一直’下雪’的效果,如果返回的是false,则只执行一次

完整代码

猜你喜欢:

Flutter 轮子之气泡登录页(1)

Android 轮子之下雪效果

原创不易,您的点赞就是对我最大的支持,留下您的点赞吧~

Flutter 轮子之下雪动画(2)_第8张图片

你可能感兴趣的:(Flutter,flutter,animation)