Flutter(十五)——动画的封装与简化

前言

在上一篇的动画内容中,我们学习了基本的概念,以及动画的基本使用规则,但是,上一篇的代码真的实际项目中应用很多吗?其实不是,上一篇之所以那么介绍,只是为了让大家更了解Flutter动画的原理,其实还有更简单封装与简化的使用方式,这一篇就开始学习这些内容。

AnimatedWidget

前面动画之中,我们都是通过addListener和setState来更新UI的,然而有时候可以不用这么麻烦,通过AnimationWidget这个类就可以实现,它对addListener和setState进行了封装,隐藏了实现细节。下面,我们直接上代码来看看:

class _MyHomePageState extends State<MyHomePage> with SingleTickerProviderStateMixin{
  Animation<double> animation;
  AnimationController controller;

  initState(){
    super.initState();
    controller=AnimationController(duration: const Duration(milliseconds: 2000),vsync: this);
    animation=CurvedAnimation(parent: controller,curve: Curves.bounceIn)..addStatusListener((status){
      if(status==AnimationStatus.completed){//动画在结束时停止的状态
        controller.reverse();//颠倒
      }else if(status==AnimationStatus.dismissed){//动画在开始时就停止的状态
        controller.forward();//向前
      }
    })..addListener((){
      setState(() {
        print(animation.value);
      });
    });
    controller.forward();
  }

  @override
  void dispose() {
    controller.dispose();
    // TODO: implement dispose
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return AnimationLogo(animation: animation,);
  }
}

class AnimationLogo extends AnimatedWidget{

  AnimationLogo({Key key,Animation<double> animation})
      :super(key:key,listenable:animation);

  @override
  Widget build(BuildContext context) {
    final Animation<double> animation=listenable;
    return Scaffold(
      appBar: AppBar(
        title: Text("封装动画"),
      ),
      body: Container(
        height: animation.value*300,
        margin: EdgeInsets.symmetric(vertical: 10.0),
        width: animation.value*300,
        child: FlutterLogo(),
      ),
    );
  }

}

封装后,AnimationLogo可以通过当前自身Animation的value值来绘制自己。

AnimatedBuilder

有时候我们会使用多个AnimatedWidget,而如果多次实现AnimatedWidget,则代码就显得不那么美观了,这个时候,我们就需要考虑使用AnimatedBuilder,它的优点有:

(1)不需要知道如何渲染组件,也不需要知道如何管理动画对象

(2)继承自AnimatedWidget,可以直接当作组件来使用,且不用显式地去添加帧的监听addListener(…),然后在调用setState

(3)只调用动画组件中地build,在复杂地布局下性能有所提高

我们先来看一张组件示意图:

组件
接着我们将上面的代码进行重构,代码如下:

class _MyHomePageState extends State<MyHomePage> with SingleTickerProviderStateMixin{
  Animation<double> animation;
  AnimationController controller;

  initState(){
    super.initState();
    controller=AnimationController(duration: const Duration(milliseconds: 2000),vsync: this);
    animation=CurvedAnimation(parent: controller,curve: Curves.bounceIn)..addStatusListener((status){
      if(status==AnimationStatus.completed){//动画在结束时停止的状态
        controller.reverse();//颠倒
      }else if(status==AnimationStatus.dismissed){//动画在开始时就停止的状态
        controller.forward();//向前
      }
    })..addListener((){
      setState(() {
      });
    });
    controller.forward();
  }

  @override
  void dispose() {
    controller.dispose();
    // TODO: implement dispose
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return GrowTransition(child:AnimationLogo(),animation: animation,);
  }
}

class AnimationLogo extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Container(
      margin: EdgeInsets.symmetric(vertical: 10),
      child: FlutterLogo(),
    );
  }
}

class GrowTransition extends StatelessWidget{
  final Widget child;
  final Animation<double> animation;
  GrowTransition({this.child,this.animation});
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("AnimatedBuilder"),),
      body: Center(
        child: AnimatedBuilder(
          animation: this.animation,
          builder: (BuildContext context,Widget child){
            return Container(
              height: animation.value*300,
              width: animation.value*300,
              child: child,
            );
          },
          child: this.child,
        ),
      ),
    );
  }
}

前面的代码基本一样,就是后面的代码变更了,所以重点看后面的代码就行。其实在Flutter开发中,通过AnimatedBuilder方式还封装了很多动画,比如SizeTransition,ScaleTransition,RotationTransition,FadeTransition,FractionalTranslation等。很多时候我们都可以反复使用这些预置的过渡类。效果图更前篇文章差不多,这里就不展示了。

发布了105 篇原创文章 · 获赞 139 · 访问量 94万+

猜你喜欢

转载自blog.csdn.net/liyuanjinglyj/article/details/104136939