(Flutter)交錯動畫【譯】

交錯動畫

你將學習到什么:

  • 交錯動畫由序列或重疊的動畫組成苞氮。
  • 要創(chuàng)建交錯動畫,使用多個動畫對象。
  • 一個AnimationController控制所有動畫。
  • 每個動畫對象在間隔期間指定動畫椒舵。
  • 對于要設(shè)置動畫的每個屬性,請創(chuàng)建一個Tween约谈。

Terminology: 如果補間或補間的概念對您來說是新的笔宿,請參閱Flutter教程中的動畫

交錯的動畫是一個直截了當?shù)母拍睿阂曈X變化發(fā)生在一系列操作中,而不是一次性發(fā)生窗宇。 動畫可能是純粹順序的措伐,在下一個動畫之后會發(fā)生一次更改特纤,或者可能部分或完全重疊军俊。 它也可能有間隙,沒有發(fā)生變化捧存。

本指南介紹了如何在Flutter中構(gòu)建交錯動畫粪躬。

Examples

本指南介紹了basic_staggered_animation示例。您還可以參考更復雜的示例staggered_pic_selection昔穴。
basic_staggered_animation

顯示單個窗口小部件的一系列連續(xù)和重疊動畫镰官。 點擊屏幕會開始一個動畫届吁,可以改變不透明度眷细,大小,形狀礼搁,顏色和填充宙搬。

staggered_pic_selection

顯示從以三種尺寸之一顯示的圖像列表中刪除圖像笨腥。此示例使用兩個動畫控制器: 一個用于圖像選擇/取消選擇,另一個用于圖像刪除勇垛。 選擇/取消選擇動畫是錯開的脖母。 (要查看此效果,您可能需要增加timeDilation 值闲孤。) 選擇一個最大的圖像谆级,它會縮小,因為它在藍色圓圈內(nèi)顯示一個復選標記讼积。 接下來肥照,選擇一個最小的圖像,當復選標記消失時勤众,大圖像會擴展舆绎。 在大圖像完成展開之前,小圖像會縮小以顯示其復選標記决摧。 這種交錯行為類似于您在Google相冊中看到的行為亿蒸。

以下視頻演示了basic_staggered_animation執(zhí)行的動畫:


StaggerDemo.gif

在視頻中凑兰,您會看到單個小部件的以下動畫,該小部件以帶有略微圓角的邊框藍色方塊開始边锁。 該方塊按以下順序運行更改:

  1. 淡入
  2. 擴大
  3. 向上移動時變得更高
  4. 轉(zhuǎn)變?yōu)橛羞吔绲膱A圈
  5. 將顏色更改為橙??色

向前跑之后姑食,動畫反向運行。

Flutter新手?
本頁假定您知道如何使用Flutter的小部件創(chuàng)建布局茅坛。 有關(guān)更多信息音半,請參閱在Flutter中構(gòu)建布局.

交錯動畫的基本結(jié)構(gòu)

重點是什么?

  • 所有動畫都由同一個AnimationController驅(qū)動贡蓖。
  • 無論動畫實時持續(xù)多長時間曹鸠,控制器的值必須介于0.0和1.0之間。
  • 每個動畫的間隔介于0.0和1.0之間斥铺。
  • 對于在間隔中設(shè)置動畫的每個屬性彻桃,請創(chuàng)建一個Tween。 Tween指定該屬性的開始值和結(jié)束值晾蜘。
  • Tween生成一個由控制器管理的Animation對象邻眷。

下圖顯示了basic_staggered_animation示例中使用的間隔。 您可能會注意到以下特征:

  • 不透明度在時間軸的前10%期間發(fā)生變化剔交。
  • 不透明度的變化與寬度的變化之間存在微小的差距肆饶。
  • 在最后25%的時間線中沒有任何動畫。
  • 增加填充使小部件看起來向上岖常。
  • 將邊框半徑增加到0.5驯镊,將帶圓角的方形轉(zhuǎn)換為圓形。
  • 填充和邊界半徑變化發(fā)生在相同的精確間隔期間竭鞍,但它們不必板惑。
StaggeredAnimationIntervals.png

要設(shè)置動畫:

  • 創(chuàng)建一個管理所有動畫的AnimationController。
  • 為每個動畫屬性創(chuàng)建一個Tween笼蛛。
    • Tween定義了一系列值洒放。
    • Tween的animate方法需要parent控制器,并為該屬性生成一個Animation滨砍。
  • 在動畫curve屬性上指定間隔往湿。

當控制動畫的值更改時,新動畫的值會更改惋戏,從而觸發(fā)UI更新领追。

以下代碼為width屬性創(chuàng)建補間。 它構(gòu)建一個CurvedAnimation 响逢,指定一個緩和的曲線绒窑。 有關(guān)其他可用的預定義動畫曲線,請參閱曲線舔亭。

width = Tween<double>(
  begin: 50.0,
  end: 150.0,
).animate(
  CurvedAnimation(
    parent: controller,
    curve: Interval(
      0.125, 0.250,
      curve: Curves.ease,
    ),
  ),
),

beginend 的值不必是雙倍的些膨。下面的代碼使用BorderRadius.circular()borderRadius屬性(控制方塊角的圓度)構(gòu)建補間蟀俊。

borderRadius = BorderRadiusTween(
  begin: BorderRadius.circular(4.0),
  end: BorderRadius.circular(75.0),
).animate(
  CurvedAnimation(
    parent: controller,
    curve: Interval(
      0.375, 0.500,
      curve: Curves.ease,
    ),
  ),
),

完成交錯的動畫

與所有交互式小部件一樣,完整的動畫由小部件對組成:無狀態(tài)小部件和有狀態(tài)小部件订雾。

無狀態(tài)窗口小部件指定補間肢预,定義Animation對象,并提供build()函數(shù)洼哎,負責構(gòu)建窗口小部件樹的動畫部分烫映。

有狀態(tài)小部件創(chuàng)建控制器,播放動畫噩峦,并構(gòu)建小部件樹的非動畫部分锭沟。 在屏幕中的任何位置檢測到點擊時,動畫開始识补。

basic_staggered_animation’s main.dart的完整代碼

無狀態(tài)小部件:StaggerAnimation

在無狀態(tài)小部件StaggerAnimation中族淮, build()函數(shù)實例化一個AnimatedBuilder - 一個用于構(gòu)建動畫的通用小部件。 AnimatedBuilder構(gòu)建一個小部件并使用Tweens的當前值配置它李请。 該示例創(chuàng)建一個名為_buildAnimation()的函數(shù)(執(zhí)行實際的UI更新)瞧筛,并將其分配給其builder屬性。 AnimatedBuilder監(jiān)聽來自動畫控制器的通知导盅,在值發(fā)生變化時將小部件樹標記為臟。 對于動畫的每個刻度揍瑟,值都會更新白翻,從而調(diào)用_buildAnimation()

class StaggerAnimation extends StatelessWidget {
  StaggerAnimation({ Key key, this.controller }) :

    // Each animation defined here transforms its value during the subset
    // of the controller's duration defined by the animation's interval.
    // For example the opacity animation transforms its value during
    // the first 10% of the controller's duration.

    opacity = Tween<double>(
      begin: 0.0,
      end: 1.0,
    ).animate(
      CurvedAnimation(
        parent: controller,
        curve: Interval(
          0.0, 0.100,
          curve: Curves.ease,
        ),
      ),
    ),

    // ... Other tween definitions ...

    super(key: key);

  final Animation<double> controller;
  final Animation<double> opacity;
  final Animation<double> width;
  final Animation<double> height;
  final Animation<EdgeInsets> padding;
  final Animation<BorderRadius> borderRadius;
  final Animation<Color> color;

  // This function is called each time the controller "ticks" a new frame.
  // When it runs, all of the animation's values will have been
  // updated to reflect the controller's current value.
  Widget _buildAnimation(BuildContext context, Widget child) {
    return Container(
      padding: padding.value,
      alignment: Alignment.bottomCenter,
      child: Opacity(
        opacity: opacity.value,
        child: Container(
          width: width.value,
          height: height.value,
          decoration: BoxDecoration(
            color: color.value,
            border: Border.all(
              color: Colors.indigo[300],
              width: 3.0,
            ),
            borderRadius: borderRadius.value,
          ),
        ),
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return AnimatedBuilder(
      builder: _buildAnimation,
      animation: controller,
    );
  }
}

有狀態(tài)小部件:StaggerDemo

有狀態(tài)小部件StaggerDemo創(chuàng)建了AnimationController(規(guī)定他們的對象)绢片,指定持續(xù)時間為2000毫秒滤馍。 它播放動畫,并構(gòu)建小部件樹的非動畫部分底循。 在屏幕中檢測到點擊時動畫開始巢株。 動畫向前,然后向后熙涤。

class StaggerDemo extends StatefulWidget {
  @override
  _StaggerDemoState createState() => _StaggerDemoState();
}

class _StaggerDemoState extends State<StaggerDemo> with TickerProviderStateMixin {
  AnimationController _controller;

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

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

  // ...Boilerplate...

  Future<Null> _playAnimation() async {
    try {
      await _controller.forward().orCancel;
      await _controller.reverse().orCancel;
    } on TickerCanceled {
      // the animation got canceled, probably because we were disposed
    }
  }

  @override
  Widget build(BuildContext context) {
    timeDilation = 10.0; // 1.0 is normal animation speed.
    return Scaffold(
      appBar: AppBar(
        title: const Text('Staggered Animation'),
      ),
      body: GestureDetector(
        behavior: HitTestBehavior.opaque,
        onTap: () {
          _playAnimation();
        },
        child: Center(
          child: Container(
            width: 300.0,
            height: 300.0,
            decoration: BoxDecoration(
              color: Colors.black.withOpacity(0.1),
              border: Border.all(
                color:  Colors.black.withOpacity(0.5),
              ),
            ),
            child: StaggerAnimation(
              controller: _controller.view
            ),
          ),
        ),
      ),
    );
  }
}

資源

編寫動畫時阁苞,以下資源可能會有所幫助:

Animations landing page

列出Flutter動畫的可用文檔。 如果補間對您來說不熟悉祠挫,請查看動畫教程 那槽。

Flutter API documentation

所有Flutter庫的參考文檔。 特別是等舔,請參閱動畫庫文檔骚灸。

Flutter Gallery

演示應用程序展示了許多材料組件和其他Flutter功能。 Shrine demo實現(xiàn)了英雄動畫慌植。

Material motion spec

描述材料應用的動作甚牲。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末义郑,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子丈钙,更是在濱河造成了極大的恐慌魔慷,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,826評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件著恩,死亡現(xiàn)場離奇詭異院尔,居然都是意外死亡,警方通過查閱死者的電腦和手機喉誊,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,968評論 3 395
  • 文/潘曉璐 我一進店門邀摆,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人伍茄,你說我怎么就攤上這事栋盹。” “怎么了敷矫?”我有些...
    開封第一講書人閱讀 164,234評論 0 354
  • 文/不壞的土叔 我叫張陵例获,是天一觀的道長。 經(jīng)常有香客問我曹仗,道長榨汤,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,562評論 1 293
  • 正文 為了忘掉前任怎茫,我火速辦了婚禮收壕,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘轨蛤。我一直安慰自己蜜宪,他們只是感情好,可當我...
    茶點故事閱讀 67,611評論 6 392
  • 文/花漫 我一把揭開白布祥山。 她就那樣靜靜地躺著圃验,像睡著了一般。 火紅的嫁衣襯著肌膚如雪缝呕。 梳的紋絲不亂的頭發(fā)上澳窑,一...
    開封第一講書人閱讀 51,482評論 1 302
  • 那天,我揣著相機與錄音岳颇,去河邊找鬼照捡。 笑死,一個胖子當著我的面吹牛话侧,可吹牛的內(nèi)容都是我干的栗精。 我是一名探鬼主播,決...
    沈念sama閱讀 40,271評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼悲立!你這毒婦竟也來了鹿寨?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,166評論 0 276
  • 序言:老撾萬榮一對情侶失蹤薪夕,失蹤者是張志新(化名)和其女友劉穎脚草,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體原献,經(jīng)...
    沈念sama閱讀 45,608評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡馏慨,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,814評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了姑隅。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片写隶。...
    茶點故事閱讀 39,926評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖讲仰,靈堂內(nèi)的尸體忽然破棺而出慕趴,到底是詐尸還是另有隱情,我是刑警寧澤鄙陡,帶...
    沈念sama閱讀 35,644評論 5 346
  • 正文 年R本政府宣布冕房,位于F島的核電站,受9級特大地震影響趁矾,放射性物質(zhì)發(fā)生泄漏耙册。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,249評論 3 329
  • 文/蒙蒙 一愈魏、第九天 我趴在偏房一處隱蔽的房頂上張望觅玻。 院中可真熱鬧,春花似錦培漏、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,866評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至侧甫,卻和暖如春珊佣,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背披粟。 一陣腳步聲響...
    開封第一講書人閱讀 32,991評論 1 269
  • 我被黑心中介騙來泰國打工咒锻, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人守屉。 一個月前我還...
    沈念sama閱讀 48,063評論 3 370
  • 正文 我出身青樓惑艇,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子滨巴,可洞房花燭夜當晚...
    茶點故事閱讀 44,871評論 2 354

推薦閱讀更多精彩內(nèi)容

  • 天空灰的發(fā)白 就像兔子的尾巴 沖出象牙之口 想象沒有辦法舒展 龍川之水 流淌著工業(yè)的源頭 儀器與價值的比重 顛覆嘈...
    讀叔閱讀 417評論 0 1
  • 清晨思灌,開車途中,聽起了《蔣勛七講》中的第一講恭取,每天留出18分鐘來讀詩泰偿。 于是,我聽到了這首月圓夜蜈垮,蔣勛讀的詩: 《...
    蛻變的林林閱讀 253評論 0 1
  • 什么時候都不會太遲 老了耗跛,也能和伴侶一起爬山,一起嘮嗑攒发。 想要出發(fā)永遠不會太遲调塌。 三五好友,不用一壺酒晨继,不用...
    二十二秋初閱讀 369評論 0 0