Flutter動(dòng)畫(huà): Animation動(dòng)畫(huà)基礎(chǔ)(一)

我的博客

要使用Flutter中動(dòng)畫(huà), 首先要熟悉Flutter的動(dòng)畫(huà)基礎(chǔ)概念和相關(guān)類煎源。

  • Animation:Flutter中動(dòng)畫(huà)的核心類。
  • AnimationController:動(dòng)畫(huà)管理類纳鼎。
  • Tween:補(bǔ)間對(duì)象果元,用于計(jì)算動(dòng)畫(huà)使用的數(shù)據(jù)范圍之間的插值契耿。
  • ListenersStatusListeners:用于監(jiān)聽(tīng)動(dòng)畫(huà)狀態(tài)改變。
  • CurvedAnimation:用于定義非線性曲線動(dòng)畫(huà) 。

簡(jiǎn)單點(diǎn)說(shuō), 熟悉了上面幾個(gè)術(shù)語(yǔ)和用法, 就基本入門了Flutter的動(dòng)畫(huà)基礎(chǔ). 但是沒(méi)有一定使用經(jīng)驗(yàn), 上面的術(shù)語(yǔ)其實(shí)很抽象. Flutter的官方文檔其實(shí)講解的非常詳細(xì), 具體參見(jiàn): [Flutter中的動(dòng)畫(huà)]

先做個(gè)例子

我們還是做一個(gè)例子來(lái)說(shuō)明其簡(jiǎn)單用法.

import 'package:flutter/material.dart';

class NormalAnimationDemo extends StatefulWidget {
  @override
  _NormalAnimationDemoState createState() => _NormalAnimationDemoState();
}

class _NormalAnimationDemoState extends State<NormalAnimationDemo>
    with SingleTickerProviderStateMixin {
  AnimationController _controller;
  Animation<double> _animation;
  Duration _duration = Duration(milliseconds: 1000);

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(vsync: this, duration: _duration)
      ..addListener(() {
        // 用于實(shí)時(shí)更新_animation.value
        setState(() {});
      })
      ..addStatusListener((status) {
        if (status == AnimationStatus.completed) {
          // 監(jiān)聽(tīng)動(dòng)畫(huà)完成的狀態(tài) The animation is stopped at the end
          _controller.reverse();
        }
        if (status == AnimationStatus.dismissed) {
          // 監(jiān)聽(tīng)動(dòng)畫(huà)結(jié)束的狀態(tài) The animation is stopped at the beginning
          _controller.forward();
        }
      });
    _animation = CurvedAnimation(parent: _controller, curve: Curves.fastOutSlowIn);
    _animation = Tween<double>(begin: 0.0, end: 1.0).animate(_animation);
    _controller.forward();
  }

  @override
  void dispose() {
    _controller?.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('動(dòng)畫(huà)Demo')),
      body: Center(
        child: Container(
          width: 100 * (1 + _animation.value),
          height: 100 * (1 + _animation.value),
          child: Image.asset('assets/images/head.jpg'),
        ),
      ),
    );
  }
}

動(dòng)畫(huà)效果如下:

normal_animation

總結(jié)一下:

這個(gè)簡(jiǎn)單的例子用到了Animation, AnimationController,CurvedAnimation和Tween的概念, 還對(duì)動(dòng)畫(huà)的過(guò)程進(jìn)行了監(jiān)控.

Animation

在Flutter中碎绎,Animation對(duì)象本身和UI渲染沒(méi)有任何關(guān)系。Animation是一個(gè)抽象類描扯,它擁有其當(dāng)前值和狀態(tài)(完成或停止)。其中一個(gè)比較常用的Animation類是Animation<double>趟薄。

Flutter中的Animation對(duì)象是一個(gè)在一段時(shí)間內(nèi)依次生成一個(gè)區(qū)間之間值的類绽诚。Animation對(duì)象的輸出可以是線性的、曲線的杭煎、一個(gè)步進(jìn)函數(shù)或者任何其他可以設(shè)計(jì)的映射憔购。

根據(jù)Animation對(duì)象的控制方式,動(dòng)畫(huà)可以反向運(yùn)行岔帽,甚至可以在中間切換方向。

Animation還可以生成除double之外的其他類型值导绷,如:Animation<Color>Animation<Size>犀勒。

Animation對(duì)象有狀態(tài)⊥浊可以通過(guò)訪問(wèn)其value屬性獲取動(dòng)畫(huà)的當(dāng)前值贾费。

Animation對(duì)象本身和UI渲染沒(méi)有任何關(guān)系。

AnimationController

AnimationController派生自Animation<double>檐盟,因此可以在需要Animation對(duì)象的任何地方使用褂萧。 但是,AnimationController具有控制動(dòng)畫(huà)的其他方法葵萎。例如导犹,.forward()方法可以啟動(dòng)動(dòng)畫(huà)唱凯。

數(shù)字的產(chǎn)生與屏幕刷新有關(guān),因此每秒鐘通常會(huì)產(chǎn)生60個(gè)數(shù)字谎痢,在生成每個(gè)數(shù)字后磕昼,每個(gè)Animation對(duì)象調(diào)用添加的Listener對(duì)象。

當(dāng)創(chuàng)建一個(gè)AnimationController時(shí)节猿,需要傳遞一個(gè)vsync參數(shù)票从,存在vsync時(shí)會(huì)防止屏幕外動(dòng)畫(huà)(譯者語(yǔ):動(dòng)畫(huà)的UI不在當(dāng)前屏幕時(shí))消耗不必要的資源。 通過(guò)將SingleTickerProviderStateMixin添加到類定義中滨嘱,可以將stateful對(duì)象作為vsync的值峰鄙。

CurvedAnimation

CurvedAnimation 將動(dòng)畫(huà)過(guò)程定義為一個(gè)非線性曲線. 有許多種系統(tǒng)預(yù)制的曲線, 可以通過(guò)Curves.獲取。一般來(lái)說(shuō), 默認(rèn)的都是線性(Curves.linear)太雨。

Tween

默認(rèn)情況下吟榴,AnimationController對(duì)象的范圍從0.0到1.0。如果您需要不同的范圍或不同的數(shù)據(jù)類型躺彬,則可以使用Tween來(lái)配置動(dòng)畫(huà)以生成不同的范圍或數(shù)據(jù)類型的值煤墙。

例如,以下示例宪拥,Tween生成從-200.0到0.0的值:

final Tween doubleTween = Tween(begin: -200.0, end: 0.0);

Tween是一個(gè)無(wú)狀態(tài)(stateless)對(duì)象仿野,需要begin和end值。Tween的唯一職責(zé)就是定義從輸入范圍到輸出范圍的映射她君。輸入范圍通常為0.0到1.0脚作,但這不是必須的。

Tween繼承自Animatable<T>缔刹,而不是繼承自Animation<T>球涛。

Animatable與Animation相似,不是必須輸出double值校镐。例如亿扁,ColorTween指定兩種顏色之間的過(guò)渡。

final Tween colorTween = ColorTween(begin: Colors.transparent, end: Colors.black54);

Tween對(duì)象不存儲(chǔ)任何狀態(tài)鸟廓。相反从祝,它提供了evaluate(Animation animation)方法將映射函數(shù)應(yīng)用于動(dòng)畫(huà)當(dāng)前值。 Animation對(duì)象的當(dāng)前值可以通過(guò)value()方法取到引谜。evaluate函數(shù)還執(zhí)行一些其它處理牍陌,例如分別確保在動(dòng)畫(huà)值為0.0和1.0時(shí)返回開(kāi)始和結(jié)束狀態(tài)。

Tween.animate 要使用Tween對(duì)象员咽,請(qǐng)調(diào)用其animate()方法毒涧,傳入一個(gè)控制器對(duì)象。

例如贝室,以下代碼在500毫秒內(nèi)生成從0到255的整數(shù)值契讲。

final AnimationController controller = AnimationController( duration: const Duration(milliseconds: 500), vsync: this);
Animation alpha = IntTween(begin: 0, end: 255).animate(controller);

注意animate()返回的是一個(gè)Animation仿吞,而不是一個(gè)Animatable。

監(jiān)聽(tīng)

一個(gè)Animation對(duì)象可以擁有Listeners和StatusListeners監(jiān)聽(tīng)器怀泊,可以用addListener()和addStatusListener()來(lái)添加茫藏。 只要?jiǎng)赢?huà)的值發(fā)生變化,就會(huì)調(diào)用監(jiān)聽(tīng)器霹琼。

一個(gè)Listener最常見(jiàn)的行為是調(diào)用setState()來(lái)觸發(fā)UI重建务傲。 上面的例子就用于實(shí)時(shí)更新animation.value的值。

..addListener(() {
        // 用于實(shí)時(shí)更新_animation.value
        setState(() {});
      })

動(dòng)畫(huà)完成枣申、結(jié)束售葡、向前移動(dòng)或向后移動(dòng)(如AnimationStatus所定義)時(shí)會(huì)調(diào)用StatusListener。上面的例子就監(jiān)聽(tīng)了動(dòng)畫(huà)完成(AnimationStatus.completed)和結(jié)束(AnimationStatus.dismissed)的狀態(tài), 同時(shí)根據(jù)其狀態(tài)發(fā)出了Reverse和Forward命令忠藤。

..addStatusListener((status) {
        if (status == AnimationStatus.completed) {
          // 監(jiān)聽(tīng)動(dòng)畫(huà)完成的狀態(tài) The animation is stopped at the end
          _controller.reverse();
        }
        if (status == AnimationStatus.dismissed) {
          // 監(jiān)聽(tīng)動(dòng)畫(huà)結(jié)束的狀態(tài) The animation is stopped at the beginning
          _controller.forward();
        }
      })

至此, 一個(gè)簡(jiǎn)單的動(dòng)畫(huà)過(guò)程就完成了挟伙。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市模孩,隨后出現(xiàn)的幾起案子尖阔,更是在濱河造成了極大的恐慌,老刑警劉巖榨咐,帶你破解...
    沈念sama閱讀 218,546評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件介却,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡块茁,警方通過(guò)查閱死者的電腦和手機(jī)齿坷,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,224評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)数焊,“玉大人永淌,你說(shuō)我怎么就攤上這事∨宥” “怎么了遂蛀?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,911評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)干厚。 經(jīng)常有香客問(wèn)我答恶,道長(zhǎng),這世上最難降的妖魔是什么萍诱? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,737評(píng)論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮污呼,結(jié)果婚禮上裕坊,老公的妹妹穿的比我還像新娘。我一直安慰自己燕酷,他們只是感情好籍凝,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,753評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布周瞎。 她就那樣靜靜地躺著,像睡著了一般饵蒂。 火紅的嫁衣襯著肌膚如雪声诸。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,598評(píng)論 1 305
  • 那天退盯,我揣著相機(jī)與錄音彼乌,去河邊找鬼。 笑死渊迁,一個(gè)胖子當(dāng)著我的面吹牛慰照,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播琉朽,決...
    沈念sama閱讀 40,338評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼毒租,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了箱叁?” 一聲冷哼從身側(cè)響起墅垮,我...
    開(kāi)封第一講書(shū)人閱讀 39,249評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎耕漱,沒(méi)想到半個(gè)月后算色,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,696評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡孤个,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,888評(píng)論 3 336
  • 正文 我和宋清朗相戀三年剃允,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片齐鲤。...
    茶點(diǎn)故事閱讀 40,013評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡斥废,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出给郊,到底是詐尸還是另有隱情牡肉,我是刑警寧澤,帶...
    沈念sama閱讀 35,731評(píng)論 5 346
  • 正文 年R本政府宣布淆九,位于F島的核電站统锤,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏炭庙。R本人自食惡果不足惜饲窿,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,348評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望焕蹄。 院中可真熱鬧逾雄,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,929評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至做鹰,卻和暖如春击纬,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背钾麸。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,048評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工更振, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人喂走。 一個(gè)月前我還...
    沈念sama閱讀 48,203評(píng)論 3 370
  • 正文 我出身青樓殃饿,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親芋肠。 傳聞我的和親對(duì)象是個(gè)殘疾皇子乎芳,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,960評(píng)論 2 355