flutter 动画初探(绘制动画)

本文介绍了Flutter中基于AnimationController和AnimatedBuilder的动画原理,通过AnimationController设置动画持续时间及控制动画状态。在实践中,创建了一个简单的圆形路径转圈动画,当点击时,圆形路径会填充并完成一圈的旋转,以此作为加载或刷新的动画效果。文章还提醒注意AnimationController的正确销毁。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

今天开始学习flutter中动画的使用,什么叫绘制动画呢,其实我想表达的意思是,结合上一篇文章中学习的绘制,本文中让它动起来?

准备着手做一个类似于加载圈的动画,比如说下拉刷新,或者页面网络请求加载时的动画,这篇文章先做一个建议版的,来个动画入门?

先对flutter中的动画做个简单介绍:

Flutter的动画也不复杂,关键词AnimationController

Flutter中的动画是基于Animation,这个对象本身是一个抽象类,在一段时间内依次产生一些值。我们使用封装好的AnimationController来做动画,它在屏幕刷新的每一帧,产生一个新的值,默认情况是在给定的时间段内线性的生成0.0到1.0的数字。

需要注意的是在使用AnimationController的时候需要结合TickerProvider,因为只有在TickerProvider下才能配置AnimationController中的构造参数vsyncTickerProvider是一个抽象类,所以我们一般使用它的实现类TickerProviderStateMixinSingleTickerProviderStateMixin

那么,这两种方式有什么不同呢? 如果整个生命周期中,只有一个AnimationController,那么就使用SingleTickerProviderStateMixin,因为此种情况下,它的效率相对来说要高很多。反之,如果有多个AnimationController,就是用TickerProviderStateMixin

还有duration属性可以设置持续时间。还有一些方法可以控制动画forward启动,reverse反转,repeat重复。

AnimationControlleraddListeneraddStatusListener方法可以添加监听,一个是值监听一个是状态监听。值监听常用在调用setState来触发UI重建来实现动画,状态监听用在动画状态变化的时候执行一些方法,比如在动画结束时反转动画。

简单了解完上述的这些属性和方法之后,就可以做一个简单地动画来练练手了

这里的需求是一段圆弧在给定的圆形路径上不断转圈,在点击click之后,整个圆形路径填充一圈,然后结束

这里我们先进行绘制,顺便复习一下上一篇文章里面学到的内容:

class MyPainter extends CustomPainter {
  Color lineColor;
  Color completeColor;
  double startPercent;//圆弧转动时 开始的位置
  bool isComplete = false;
  double width;

  MyPainter(
      {this.lineColor,
      this.completeColor,
      this.startPercent,
      this.width,
      this.isComplete : false});
  @override
  void paint(Canvas canvas, Size size) {
    Paint line = Paint()
      ..color = lineColor
      ..strokeCap = StrokeCap.round
      ..style = PaintingStyle.stroke
      ..strokeWidth = width;

    Paint complete = Paint()
      ..color = completeColor
      ..strokeCap = StrokeCap.round
      ..style = PaintingStyle.stroke
      ..strokeWidth = width;

    Offset center = Offset(size.width / 2, size.height / 2); //  坐标中心
    double radius = min(size.width / 2, size.height / 2); //  半径
    canvas.drawCircle(
    //  画圆方法
        center,
        radius,
        line);

    double arcAngle = isComplete == true ? startPercent : 2 * pi / 10;

    //画转动的圆弧
    canvas.drawArc(Rect.fromCircle(center: center, radius: radius),
        isComplete == true ? 2 * pi  : startPercent, arcAngle, false, complete);
  }

  @override
  bool shouldRepaint(MyPainter oldDelegate) {
    return startPercent != oldDelegate.startPercent;
  }
}

所谓动画,大概就是动起来的画吧,现在画已经有了,下一步就是让他动起来

class _HomeContentState extends State<HomeContent>
    with TickerProviderStateMixin {
  double percentage = 0.0;
  AnimationController percentageAnimationController;
  bool isClick = false;

  @override
  void initState() {
    super.initState();
    percentageAnimationController = new AnimationController(
        vsync: this, duration: new Duration(milliseconds: 2000))
      ..repeat()
      ..addListener(() {
        setState(() {
          percentage = percentageAnimationController.value * pi * 2;
        });
      });
  }

  @override
  Widget build(BuildContext context) {
    return new Center(
      child: new Container(
        height: 200.0,
        width: 200.0,
        child: new CustomPaint(
          foregroundPainter: new MyPainter(
              lineColor: Colors.lightBlueAccent,
              completeColor: Colors.blueAccent,
              startPercent: percentage,
              isComplete: isClick,
              width: 8.0),
          child: new Padding(
            padding: const EdgeInsets.all(8.0),
            child: new RaisedButton(
                color: Colors.green,
                splashColor: Colors.transparent,
                shape: new CircleBorder(),
                child: new Text("Click"),
                onPressed: () {
                  setState(() {
                    isClick = true;

                    percentageAnimationController.forward(from: 0.0);
                  });
                 
                }),
          ),
        ),
      ),
    );
  }
}

就是上面介绍动画里面的步骤,就不再重复了,当然也可以换一种写法用AnimatedBuilder,就不需要setState了

Widget build(BuildContext context) {
    return new Center(
      child: new Container(
        height: 200.0,
        width: 200.0,
        child: AnimatedBuilder(animation: percentageAnimationController, builder: (context, child) {
          return new CustomPaint(
          foregroundPainter: new MyPainter(
              lineColor: Colors.lightBlueAccent,
              completeColor: Colors.blueAccent,
              startPercent: percentage,
              isComplete: isClick,
              width: 8.0),
          child: new Padding(
            padding: const EdgeInsets.all(8.0),
            child: new RaisedButton(
                color: Colors.green,
                splashColor: Colors.transparent,
                shape: new CircleBorder(),
                child: new Text("Click"),
                onPressed: () {
                    isClick = true;
                    percentageAnimationController.forward(from: 0.0);
                 
                }),
          ),
        );
        })
        
      ),
    );
  }

有一点需要注意的是,controller的销毁

@override
  void dispose() {
    percentageAnimationController.dispose();
    super.dispose();
  }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值