要在 Flutter 中使用動畫,可以有多種不同的方式,這視你的目的而定,可以觀看〈How to choose which Flutter Animation Widget is right for you? 〉中的說明,得到些初淺的概念。
簡單來說,如果你只是想讓 Widget 在特性變化(尺寸、顏色…)方面,可以展現出一些動畫,Flutter 提供了一些既有的元件,可以讓你輕鬆展現效果,如果這些元件無法滿足,才進一步考慮自行控制 AnimationController
等細節來做這些事,如果你希望的是更複雜的繪圖變化(像是遊戲畫面),就要瞭解更多動畫的底層細節。
這邊會先從讓 Widget 在特性變化方面,可以展現出一些動畫效果開始,首先來看個範例:
import 'package:flutter/material.dart';
void main() => runApp(
MaterialApp(
home: Caterpillar(),
)
);
class Caterpillar extends StatefulWidget {
@override
State<StatefulWidget> createState() => _CaterpillarState();
}
class _CaterpillarState extends State<Caterpillar> {
var zoom_in = true;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
'openhome.cc'
),
),
body: Center(
child: Container(
width: zoom_in ? 100 : 300,
child: Image.network('https://openhome.cc/Gossip/images/caterpillar.jpg')
)
),
floatingActionButton: FloatingActionButton(
onPressed: () => setState(() {
zoom_in = !zoom_in;
}),
tooltip: zoom_in ? 'Zoom in' : 'Zoom out',
child: Icon(zoom_in ? Icons.zoom_in : Icons.zoom_out),
),
);
}
}
這個範例在按下按鈕後,只會純綷地放大或縮小圖案,沒有動畫效果:
如果想以漸漸放大或縮小的動畫來展現呢?你需要做的,就是將這段:
...
body: Center(
child: Container(
width: zoom_in ? 100 : 300,
child: Image.network('https://openhome.cc/Gossip/images/caterpillar.jpg')
)
)
改為這段:
...
body: Center(
child: AnimatedContainer(
width: zoom_in ? 100 : 300,
child: Image.network('https://openhome.cc/Gossip/images/caterpillar.jpg'),
duration: Duration(seconds: 1),
)
),
最大的差別就是,使用了 AnimatedContainer
來代替 Container
,並設定了 duration
為 1 秒,也就是設定動畫持續時間,就可以呈現出以下的效果:
100 與 300 之間的尺寸變化,AnimatedContainer
預設會使用線性內插來計算,這可以由 curve
特性控制,它的預設值是 Curves.linear
,在 Curves 文件,你可以看到各種不同的變化曲線,其中也有標示各曲線大致的效果展示,例如,改用 Curves.slowMiddle
:
...
body: Center(
child: AnimatedContainer(
width: zoom_in ? 100 : 300,
child: Image.network('https://openhome.cc/Gossip/images/caterpillar.jpg'),
duration: Duration(seconds: 1),
curve: Curves.slowMiddle,
)
),
來看看效果:
像 AnimatedContainer
這類元件,只要簡單地設置 duration
、curve
之類特性,無需接觸 AnimationController
等細節,被稱為隱式動畫 Widget,一切細節都由 AnimatedContainer
隱式地控制,AnimatedContainer
的文件 中可以看到,它是 ImplicitlyAnimatedWidget
的子類:
Widget > StatefulWidget > ImplicitlyAnimatedWidget > AnimatedContainer
可以控制並不限於尺寸,AnimatedContainer
的文件 中可以看到還包含了顏色的漸變效果範例:
在 ImplicitlyAnimatedWidget
的文件 中,可以看到一些與非動畫元件相對應的隱式動畫元件,像是 AnimatedAlign
對應了 Align
、AnimatedOpacity
對應了 Opacity
等,對於 Widget 元件特性變更時希望展現動畫效果,可以先看看這些元件是否適用。