阅读 1901

Flutter 动画入门

官方动画介绍

Widget动起来

1.使用Animation

原理类似于Android的属性动画,和Widget分离,在一定时间内生成一系列的值,值可以是int,double,color或者string等等,每隔N毫秒,或者N秒钟获取到最新的值去替换掉Widget上的值,同时刷新布局,如果刷新间隔足够小就能起到动画的作用,例如构造一个Widget,他的width,height由动画来控制,一定时间动态更新值使Widget产生动效:

new Container(
        margin: new EdgeInsets.symmetric(vertical: 10.0),
        height: animation.value,     
        width: animation.value,
        child: new FlutterLogo(),
      ),
复制代码

接下来看下如何使用Animation构建一个动态更新Widget的简单场景

  • 导入Animationimport 'package:flutter/animation.dart';
  • 创建StatefulWidget,创建Animation的实现类AnimationController,来构造一个最简单的属性动画,并且应用到Widget上。
class TestPage extends StatefulWidget {
  @override
  _TestPageState createState() => _TestPageState();
}

class _TestPageState extends State<TestPage>
    with SingleTickerProviderStateMixin {
  AnimationController animationController;

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    animationController = AnimationController(
        vsync: this, duration: Duration(milliseconds: 1000));
    animationController.addListener(() {
      setState(() {});
    });
    animationController.forward(); //启动动画
  }

  @override
  Widget build(BuildContext context) {
    print('tag' + animationController.value.toString());
    return Center(
      child: Container(
        width: animationController.value,
        height: animationController.value * 100,
        color: Colors.red,
      ),
    );
  }
}
复制代码

可以看到回调打印的是从0-1的值,要返回其他类型的数值就需要用到TweenTween有许多子类例如:

image.png
来帮助我们实现更多的效果,使用Tween来实现从0-100的数值变换

class _TestPageState extends State<TestPage>
    with SingleTickerProviderStateMixin {
  AnimationController animationController;
  Animation animation;
  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    animationController = AnimationController(
        vsync: this, duration: Duration(milliseconds: 1000));
    animation = Tween(begin: 0.0,end: 100.0).animate(animationController);
    animationController.addListener(() {
      setState(() {});
    });
    animationController.forward(); //启动动画

  }

  @override
  Widget build(BuildContext context) {
    print('tag' + animationController.value.toString());
    return Center(
      child: Container(
        width: animation.value.toDouble(),
        height: animation.value.toDouble() ,
        color: Colors.red,
      ),
    );
  }
}
复制代码
2.使用AnimatedWidget来简化代码AnimatedWidget,省去了addListener()以及setState()交给AnimatedWidget处理,感觉也没省掉很多。。
class TestContainer extends AnimatedWidget {
  TestContainer({Key key,Animation animation})
      : super(key: key, listenable: animation);
 @override
  Widget build(BuildContext context) {
    // TODO: implement build
   Animation animation = listenable;
    return    Center(
      child: Container(
        width: animation.value.toDouble(),
        height: animation.value.toDouble() ,
        color: Colors.red,
      ),
    );
  }
}

class TestPage extends StatefulWidget {
  @override
  _TestPageState createState() => _TestPageState();
}

class _TestPageState extends State<TestPage>
    with SingleTickerProviderStateMixin {
  AnimationController animationController;
  Animation animation;
  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    animationController = AnimationController(
        vsync: this, duration: Duration(milliseconds: 1000));
    animation = Tween(begin: 0.0,end: 100.0).animate(animationController);
    animationController.forward(); //启动动画
  }

  @override
  Widget build(BuildContext context) {
    return TestContainer(animation: animation,);
  }
}
复制代码
3.使用AnimatedWidget相关Api来再次简化代码,例如使用RotationTransitionWidget在3秒钟内旋转360度

class TestPage extends StatefulWidget {
  @override
  _TestPageState createState() => _TestPageState();
}

class _TestPageState extends State<TestPage>
    with SingleTickerProviderStateMixin {
  AnimationController animationController;
  Animation animation;

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    animationController = AnimationController(
        vsync: this, duration: Duration(seconds: 10));
    animation = Tween(begin: 0.0, end: 1).animate(animationController);
    animationController.forward(); //启动动画
  }

  @override
  Widget build(BuildContext context) {
    return RotationTransition(turns: animation,
      child: Center(
          child: Container(color: Colors.red, width: 100, height: 100,)),);
  }
}
复制代码
4.对动画过程进行监听
animation.addStatusListener((status) {
      if (status == AnimationStatus.completed) {
        controller.reverse();
      } else if (status == AnimationStatus.dismissed) {
        controller.forward();
      }
    });
复制代码
5.使用AnimationBuilder,将控件和动画的控制过程进行封装
class TestTransition extends StatelessWidget {
  TestTransition({this.child, this.animation});

  final Widget child;
  final Animation<double> animation;

  Widget build(BuildContext context) {
    return new Center(
      child: new AnimatedBuilder(
          animation: animation,
          builder: (BuildContext context, Widget child) {
            return new Container(
                height: animation.value, width: animation.value, child: child);
          },
          child: child),
    );
  }
}

class TestPage extends StatefulWidget {
  @override
  _TestPageState createState() => _TestPageState();
}

class _TestPageState extends State<TestPage>
    with SingleTickerProviderStateMixin {
  AnimationController animationController;
  Animation animation;

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    animationController =
        AnimationController(vsync: this, duration: Duration(seconds: 10));
    animation = Tween(begin: 0.0, end: 100.0).animate(animationController);
    animationController.forward(); //启动动画
  }

  @override
  Widget build(BuildContext context) {
    return TestTransition(
      child: Center(
          child: Container(
        color: Colors.red,
      )),
      animation: animation,
    );
  }
}
复制代码
关注下面的标签,发现更多相似文章
评论