この記事はFlutter 全部俺 Advent Calendar 16日目の記事です。
このアドベントカレンダーについて
このアドベントカレンダーは @itome が全て書いています。
基本的にFlutterの公式ドキュメントとソースコードを参照しながら書いていきます。誤植や編集依頼はTwitterにお願いします。
応用的なアニメーションを作る手順
Flutterのカスタムアニメーションを作るときは、
AnimationController
の用意- 各種
Tween
の割り当て Animation
のWidgetへの割り当て
の順番で考えていきます。
AnimationController
の用意
アニメーションを扱うWidgetはTickerProviderStateMixin
などを使いやすいように、
StatefulWidget
にしておくのがいいです。
まずは、initState
でActionController
を用意しておきましょう。
AnimationController _controller;
@override
void initState() {
super.initState();
_controller = AnimationController(
duration: const Duration(milliseconds: 300),
vsync: this,
);
}
各種Tween
の割り当て
作ったActionCreator
にTween
を割り当てて0.0
~1.0
のdouble
値を
必要な値にマッピングしたAnimation
を作ります。
AnimationController
のdrive
関数にTween
を渡すか、
Tween
のanimate
関数にAnimationController
を渡すことで、Animation
が取得できます。
複数のTween
をつなげることもできます。例えばTweenA
とTweenB
をつなげると
元の値(0.0~1.0) → TweenAで変換した値 →TweenBで変換した値
のようになります。つまり、以下のコードは全て同じ挙動をします。ケースに分けて使い分けましょう。
...
Animation<Color> _animation;
@override
void initState() {
...
final curvedAnimation = CurveTween(curve: Curves.bounceIn).animate(_controller);
_animation = ColorTween(begin: Colors.blue, end: Colors.red,).animate(_controller);
}
...
Animation<Color> _animation;
@override
void initState() {
...
_animation = _controller
.drive(CurveTween(curve: Curves.bounceIn))
.drive(ColorTween(begin: Colors.blue, end: Colors.red));
}
...
Animation<Color> _animation;
@override
void initState() {
...
_animation = ColorTween(begin: Colors.blue, end: Colors.red)
.chain(CurveTween(curve: Curves.bounceIn))
.animate(_controller);
}
Animation
のWidgetへの割り当て
Animation
の現在の値が_animation.value
で取得できるので、Widgetのパラメーターとして使います。
@override
Widget build(BuildContext context) {
return Container(color: _animation.value)
}
しかし、これでは_animation
の値が変化してもWidgetの色を変えることができないので、
AnimatedBuilder
を使います。
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: _animation,
builder: (context, _) {
return Container(color: _animation.value)
},
);
}
AnimatedBuilder
はanimation:
に渡したAnimation
の値が変わると
builder
で作られるWidgetが再描画されるWidgetです。
これを使うことで_animation
の値に合わせてWidgetの色が変わるようになります。
また、AnimatedWidget
を継承してWidgetをつくることでも、値の変化に対応することが可能です。
AnimatedWidget
の場合も仕組みは同じで、super(listenable: )
に渡したAnimation
が更新される
たびにbuild
関数が再実行されます。
class ColorTransition extends AnimatedWidget {
const ColorTransition({Animation color}): super(listenable: color);
Animation<Color> get _color => listenable;
@override
Widget build(BuildContext context) {
return Container(color: _color.value);
}
}
Animated
系WidgetとTransition
系Widget
ここまではアニメーションをすべて自前で実装する手順を紹介していましたが、 デフォルトで用意されているWidgetを使うことで、もっと手軽にアニメーションを組むことができるようになります。
FlutterにはAnimatedContainer
やAnimatedTheme
など、Animated~
という名前のWidgetと
SlideTransition
やFadeTransition
などの~Transition
という名前のWidgetがあります。
これらはどちらもアニメーションを行うWidgetで、AnimatedPositioned
とPositionedTransition
のように
同じアニメーションをできるWidgetがそれぞれ用意されていたりするのでややこしいですが、
両者の違いは自前でAnimationController
を持っているかどうかです。
Animated
系Widgetは自前でAnimationController
を持っているので、こうなってほしいという状態を渡すだけで
勝手にそこに向かって動いてくれます。
int _padding = 0;
@override
Widget build(BuildContext context) {
return Stack(
children: <Widget>[
AnimatedPositioned(
top: 0,
left: _padding,
width: 100,
height: 100,
duration: const Duration(milliseconds: 500),
curve: Curves.easeInOut,
child: ...,
),
],
);
}
上のコードでは_padding
の値をsetState(() => { _padding = ... })
で変えるだけで、
500ミリ秒かけてアニメーションをしてくれます。
一方Transition
系Widgetは自前ではAnimationController
を持っていないので、そとから渡してあげる必要があります。
@override
Widget build(BuildContext context) {
return Stack(
children: <Widget>[
PositionedTransition(
rect: _animationController.drive(
RelativeRectTween(
begin: RelativeRect.fromLTRB(0, 0, 100, 100),
end: RelativeRect.fromLTRB(200, 0, 100, 100),
),
),
child: ...,
)
],
);
}
Animated
系WidgetはこちらでAnimationController
を用意しなくていい分、より手軽に使うことができます。
一方こちらからAnimationController
を渡せるTransition
は、アニメーションを途中で止めたり逆再生したりと
Animated
系Widgetではできなかったような柔軟な操作もできます。
目的のアニメーションがAnimated
系にもTransition
系にも用意されている場合は、まずAnimated
系Widgetから検討してみて、
それでもうまくアニメーションが作れなかったときに、Transition
系Widgetを試してみるのがいいと思います。
どのようなAnimated
系WidgetやTransition
系Widgetが用意されているかは、
monoさんの以下の記事を参考にしてください。
Flutterのお手軽にアニメーションを扱えるAnimated系Widgetをすべて紹介
https://link.medium.com/7471nO5Mi2
FlutterのTransition系アニメーションWidgetをすべて紹介
15日目: Flutterのアニメーションを理解する(前編) :
https://itome.team/blog/2019/12/flutter-advent-calendar-day15
17日目: FlutterのAnimatedWidgetを使いこなす :
https://itome.team/blog/2019/12/flutter-advent-calendar-day17