用一個demo理解一下Flutter動畫內(nèi)部的代碼流程

先上代碼:

import 'package:flutter/material.dart';

void main() {
  runApp(
    MaterialApp(
      home: Material(child: ScaleAnimationRoute()),
    ),
  );
}
//需要繼承TickerProvider,如果有多個AnimationController,則應(yīng)該使用TickerProviderStateMixin。
class _ScaleAnimationRouteState extends State<ScaleAnimationRoute> with SingleTickerProviderStateMixin {
  Animation<double> animation;
  AnimationController controller;

  initState() {
    super.initState();
    controller = new AnimationController(
      duration: const Duration(seconds: 3),
      vsync: this,
    );
    //圖片寬高從0變到300
    animation = new Tween(begin: 0.0, end: 300.0).animate(controller) //tag0
      ..addListener(() { //tag1
        setState(() => {});
      });
    //啟動動畫(正向執(zhí)行)
    controller.forward(); //tag2
  }

  @override
  Widget build(BuildContext context) {
    return new Center(
      child: Image.asset(
        "assets/banner1.png",
        width: animation.value,
        height: animation.value,
      ),
    );
  }

  dispose() {
    //路由銷毀時需要釋放動畫資源
    controller.dispose();
    super.dispose();
  }
}

然后上圖:


flutter動畫代碼流程.jpg

圖片較大請放大看,然后開始分析:

  1. tag0開始,這步生成了一個Tween,并設(shè)置了beginend兩個屬性,然后調(diào)用animate方法,該方法內(nèi)部創(chuàng)建了一個_AnimatedEvaluation對象,這是一個Animation實例,然后返回設(shè)置給了引用animation,這步操作在_AnimatedEvaluation內(nèi)部保存了Tween.animate方法傳入的參數(shù)AnimationControllerTween自身
  2. 然后看tag1,該步驟調(diào)用了_AnimatedEvaluationaddListener方法,_AnimatedEvaluation是從父類AnimationWithParentMixin繼承的該方法,在父類AnimationWithParentMixin里該方法的實現(xiàn)如下:
  // keep these next five dartdocs in sync with the dartdocs in Animation<T>

  /// Calls the listener every time the value of the animation changes.
  ///
  /// Listeners can be removed with [removeListener].
  void addListener(VoidCallback listener) => parent.addListener(listener);

其中parentTween.animate這步傳入的AnimationController,所以執(zhí)行的是AnimationControlleraddListener方法,所以監(jiān)聽的就是原始發(fā)送動畫數(shù)據(jù)的類實例,后面不管嵌套多少層動畫,原始數(shù)據(jù)都是從AnimationController這里獲取的值,范圍是0.0-1.0,然后看一下AnimationController這個類:

class AnimationController extends Animation<double>
  with AnimationEagerListenerMixin, AnimationLocalListenersMixin, AnimationLocalStatusListenersMixin {
...
}

省略不相關(guān)代碼,只看繼承結(jié)構(gòu),AnimationControlleraddListener實現(xiàn)在父類AnimationLocalListenersMixin里面,所以tag1這步就把值改變時的監(jiān)聽方法保存到了AnimationController

  1. 然后看tag2,調(diào)用AnimationControllerforward方法開始動畫后,方法內(nèi)部執(zhí)行_animateToInternal方法,然后animateToInternal內(nèi)部執(zhí)行notifyListeners_checkStatusChanged遍歷值監(jiān)聽和狀態(tài)監(jiān)聽列表,然后我們的監(jiān)聽方法就被回調(diào)了,我們在回調(diào)里執(zhí)行了setState方法刷新界面,然后在_ScaleAnimationRouteStatebuild方法里調(diào)用animation.value獲取了變化的值,然后我們分析animation.value這個步驟:
    3.1 因為animation_AnimatedEvaluation的實例,所以我們看這個類的內(nèi)部value的方法實現(xiàn),該方法源碼如下:
  @override
  T get value => _evaluatable.evaluate(parent);

其中_evaluatabletag0這步得知該實例是TweenparentAnimationController實例,
然后看Tween的內(nèi)部方法_evaluatable

  /// The current value of this object for the given [Animation].
  ///
  /// This function is implemented by deferring to [transform]. Subclasses that
  /// want to provide custom behavior should override [transform], not
  /// [evaluate].
  ///
  /// See also:
  ///
  ///  * [transform], which is similar but takes a `t` value directly instead of
  ///    an [Animation].
  ///  * [animate], which creates an [Animation] out of this object, continually
  ///    applying [evaluate].
  T evaluate(Animation<double> animation) => transform(animation.value);

Tweenevaluate方法內(nèi)部執(zhí)行transform(animation.value),其中animationAnimationControllerAnimationControlleranimationvalue范圍是0.0-1.0,transform內(nèi)部是實際將0.0-1.0轉(zhuǎn)換成了對應(yīng)的值,也就是頁面調(diào)用animation(這個是我們的測試代碼的animation,是_AnimatedEvaluation實例,不要和transform方法里的搞混).value方法后獲得的計算好的值,可以看一下Tweentransform方法

  @override
  T transform(double t) {
    if (t == 0.0)
      return begin;
    if (t == 1.0)
      return end;
    return lerp(t);
  }

分析完了,這就是整個流程,復(fù)雜動畫可能會嵌套多個動畫效果,但是萬變不離其宗,原理都是一樣的,圖片里的[]實際就是(),但是這個starUML用了小括號后面就不能打字了,所以看的時候不要在這里迷糊就好,有問題請在下面留言,一起學(xué)習(xí)。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容