Flutter Animation(1)動畫的簡單使用

小德_koude發表於2019-01-21

在動畫過程中,需要兩個部分:

  1. 第一個就是動畫控制類,它不需要知道在螢幕上顯示什麼。
  2. 第二個就是實際上的UI元素

1. 動畫控制類

動畫控制類有兩部分:

  1. Animation

    Animation類物件是一個抽象類,支援泛型,我們常用的是Animation<double>,當然這裡不僅僅是double,可以是任意一個物件。Animation物件本身和UI渲染沒有任何關係,而是用於生產動畫過程中的值,用這個值來控制動畫,也能獲取當前動畫的狀態(正在播放中,還是結束等),也能獲取動畫播放過程中的當前值。而且Animation類有很多不同的子類,用於實現不同的動畫效果,我們下篇在將。

  2. AnimationController

    AnimationController一方面是用來管理Animation,比如動畫的開關,另一方面,AnimationControllerAnimation還有另外一種關係,就是AnimationController是輸入,是X,它的範圍是從0.0到1.0的數字,經過Animation裡定義的f(),對映到對應的Y值,

所以AnimationAnimationController是在動畫中比不可少的元素,而且這兩個一定是搭配使用的。看程式碼:

//定義的AnimationController,動畫時長2000ms
AnimationController controller = AnimationController(
    vsync: this, duration: const Duration(milliseconds: 2000));

//Tween是Animation的子類,其實是定義了一種f(),Y的值是從50到200
//.animate(controller)是一定要呼叫的
Animation<double> animation = Tween(begin: 50.0, end: 200.0).animate(controller);

//動畫控制,開始播放
controller.forward();
複製程式碼

2 使用動畫

講完了動畫控制類,這個動畫控制類怎麼運用到UI元素上呢?

總共有三種方法:

  1. 原始方法

Animation的值直接用到widget的屬相上,用這種方法時,一定要記得Animation裡要新增動畫的監聽addListener方法,addListener方法裡要呼叫setState(() {})

因為雖然Animation的值變了,但如果不呼叫setState(() {})的話,widget就不會重新繪製。

    class AnimApp extends StatefulWidget {
      @override
      State<StatefulWidget> createState() {
        return _AnimAppState();
      }
    }
    
    class _AnimAppState extends State<AnimApp> with SingleTickerProviderStateMixin {
      AnimationController controller;
      Animation<double> animation;
    
      @override
      void initState() {
        super.initState();
    
        controller = AnimationController(
            vsync: this, duration: const Duration(milliseconds: 2000));
    
        animation = Tween(begin: 50.0, end: 200.0).animate(controller)
          ..addListener(() {
            setState(() {});
          });
    
        controller.forward();
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
            body: Center(
          child: Container(
            width: animation.value,
            height: animation.value,
            decoration: BoxDecoration(color: Colors.redAccent),
          ),
        ));
      }
    
      @override
      void dispose() {
        controller.dispose();
        super.dispose();
      }
    }
複製程式碼
  1. AnimatedWidget

    AnimatedWidget是Flutter將動畫封裝成了Widget,更方便使用,而且不需要呼叫setState()AnimatedWidget也有很多子類,這次先不介紹,先看它的普通使用,AnimatedWidget需要一個Animation的引數:

class AnimApp extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return _AnimAppState();
  }
}

class _AnimAppState extends State<AnimApp> with SingleTickerProviderStateMixin {
  AnimationController controller;
  Animation<double> animation;

  @override
  void initState() {
    super.initState();

    controller = AnimationController(
        vsync: this, duration: const Duration(milliseconds: 2000));

    animation = Tween(begin: 50.0, end: 200.0).animate(controller);

    controller.repeat();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: AnimApp2(animation: animation,),
    );
  }
}

class AnimApp2 extends AnimatedWidget {
  AnimApp2({Key key, Animation<double> animation})
      : super(key: key, listenable: animation);

  @override
  Widget build(BuildContext context) {
    final Animation<double> animation = listenable;
    return Scaffold(
        body: Center(
      child: Container(
        width: animation.value,
        height: animation.value,
        decoration: BoxDecoration(color: Colors.redAccent),
      ),
    ));
  }
}
複製程式碼
  1. AnimatedBuilder

    前面的AnimatedWidget,我要是每實現一個動畫就單獨抽出來一個class檔案來寫Widget,太複雜了,所以有了AnimatedBuilderAnimatedBuilder可以更方便的為Widget新增動畫,看程式碼:

    class AnimApp extends StatefulWidget {
      @override
      State<StatefulWidget> createState() {
        return _AnimAppState();
      }
    }
    
    class _AnimAppState extends State<AnimApp> with SingleTickerProviderStateMixin {
      AnimationController controller;
      Animation<double> animation;
    
      @override
      void initState() {
        super.initState();
    
        controller = AnimationController(
            vsync: this, duration: const Duration(milliseconds: 2000));
    
        animation = Tween(begin: 50.0, end: 200.0).animate(controller);
    
        controller.repeat();
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          body: AnimatedBuilder(
            animation: animation,
            builder: (context, child) {
              return Center(
                child: Container(
                  width: animation.value,
                  height: animation.value,
                  decoration: BoxDecoration(color: Colors.redAccent),
                ),
              );
            },
          ),
        );
      }
    }
複製程式碼

相關文章