【Flutter】まじでわからんAnimationControllerを整理する
AnimationController難しくないですか?
整理しよう。
まずアニメーションってくらいだから、StatefulWidgetが大枠なのは自明。
class AnimatedProgressIndicator extends StatefulWidget
なにかの値の変化を検知してそのアニメーションを動かすとするならば、
その検知対象をもらう必要があり。
コンストラクタでvalueにもらう。
class AnimatedProgressIndicator extends StatefulWidget {
final double value;
const AnimatedProgressIndicator({
super.key,
required this.value,
});
で、StatefulWidgetなのでstateの生成は必須。
class AnimatedProgressIndicator extends StatefulWidget {
final double value;
const AnimatedProgressIndicator({
super.key,
required this.value,
});
@override
State<AnimatedProgressIndicator> createState() {
return _AnimatedProgressIndicatorState();
}
}
ここまでは普通通りというか、教科書通り。
問題はstate側。
とりあえず、サンプルソースを貼ってから考える。
class _AnimatedProgressIndicatorState extends State<AnimatedProgressIndicator>
with SingleTickerProviderStateMixin {
late AnimationController _controller;
late Animation<Color?> _colorAnimation;
late Animation<double> _curveAnimation;
@override
void initState() {
super.initState();
_controller = AnimationController(
duration: const Duration(milliseconds: 1200),
vsync: this,
);
final colorTween = TweenSequence([
TweenSequenceItem(
tween: ColorTween(begin: Colors.red, end: Colors.orange),
weight: 1,
),
TweenSequenceItem(
tween: ColorTween(begin: Colors.orange, end: Colors.yellow),
weight: 1,
),
TweenSequenceItem(
tween: ColorTween(begin: Colors.yellow, end: Colors.green),
weight: 1,
),
]);
_colorAnimation = _controller.drive(colorTween);
_curveAnimation = _controller.drive(CurveTween(curve: Curves.easeIn));
}
initStateで、いろいろと初期化する。
AnimationControllerってなに?っていうことでとりあえずドキュメントみてみる。
アニメーション用のコントローラー。
このクラスを使用すると、次のようなタスクを実行できます。
アニメーションを順方向または逆方向に再生したり、アニメーションを停止したりできます。
アニメーションを特定の値に設定します。
アニメーションのupperBound値とlowerBound値を定義します。
物理シミュレーションを使用して、投げ飛ばすアニメーション効果を作成します。
デフォルトでは、AnimationControllerは、指定された期間中に 0.0 から 1.0 の範囲の値を線形に生成します。アニメーション コントローラーは、アプリを実行しているデバイスが新しいフレームを表示する準備ができるたびに、新しい値を生成します (通常、この速度は 1 秒あたり約 60 値です)。
わけわからん。
とりあえずアニメーションをコントロールする人。である。
で、そのコントロールする人は、drive関数をもっている。
_colorAnimation = _controller.drive(colorTween);
_curveAnimation = _controller.drive(CurveTween(curve: Curves.easeIn));
これ何してんの?って話。
chatgptにきいてみる。
User
_colorAnimation = _controller.drive(colorTween);
ってどういう意味だっけ。driveってなにするのChatGPT
_colorAnimation = _controller.drive(colorTween);というコードは、Flutterのアニメーションフレームワークにおいて、AnimationController _controllerのアニメーション出力を特定のアニメーション効果(この場合は色の変化を表すcolorTween)に「適用」する操作を行います。ここで使われるdriveメソッドは、アニメーションの値を変換して、新しいアニメーションを生成するためのメカニズムです。driveメソッドの役割と動作
値の変換: driveメソッドは、AnimationControllerからの数値のストリーム(通常は0から1まで)を、別の形式や範囲のアニメーション値に変換します。この変換にはTween(補間)オブジェクトが使用され、アニメーションの入力値に基づいて、異なる形式の出力値(この場合は色)を生成します。
アニメーションのカスタマイズ: driveを使用することで、基本的な進捗値に基づいて様々なアニメーション効果を実現できます。例えば、数値を色に変換したり、特定の範囲の数値に補間したりすることができます。
colorTweenとの組み合わせ
この例では、colorTweenはTweenSequence<Color>のインスタンスであり、複数の色の間で段階的に変化するアニメーションを定義しています。_controllerの進捗に応じて、colorTweenは適切な色値を計算し、その結果が_colorAnimationとして使用されます。具体的な使用例
dart
Copy code
_colorAnimation = _controller.drive(colorTween);
このコード行により、_controllerの進捗(0から1までの値)はcolorTweenによって色の変化に変換され、その結果のアニメーションが_colorAnimationとして利用可能になります。これをLinearProgressIndicatorのvalueColorプロパティに適用することで、進捗バーの色がアニメーションに応じて変化します。結論
driveメソッドは、基本的なアニメーションの進捗値をより具体的なアニメーション効果に「運転(ドライブ)」するために使用され、これによりFlutterでリッチでカスタマイズ可能なアニメーションを実装することができます。
ということです。
要するにTweenオブジェクトに従ったアニメーションに変換してくれるっていうことのようです。
戻り値はAnimation<U>。
Animation<U> drive<U>(Animatable<U> child)
じゃあそれどうやって使うのって話。
_AnimatedProgressIndicatorStateクラスのbuildで使う。
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: _controller,
builder: (context, child) => LinearProgressIndicator(
value: _curveAnimation.value,
valueColor: _colorAnimation,
backgroundColor: _colorAnimation.value?.withOpacity(0.4),
),
);
}
アニメーションを作るときはAnimatedBuilderをリターンするみたい。
animationプロパティにはさっきつくった、AnimationControllerのインスタンスを指定する。
valueプロパティには、実際の値を設定する。実際の値というのはアニメーション対象の値。
_curveAnimation = _controller.drive(CurveTween(curve: Curves.easeIn));
ちなみにこれはイージングカーブというアニメーションにしてねという指定らしい。
他にもeaseとか、easeInToLinearとかいろいろあるらし。
個人的わからんポイントとしてこれ。
value: _curveAnimation.value,
カーブアニメーションの値を設定しているのはなんで?って思っていた。
value: widget.value
じゃだめなの?と。
結論からいうとこれでも今回のサンプルに関しては動く。
なぜならwidget.valueの値が0から1の範囲だから。
LinearProgressIndicatorのvalueプロパティは進捗を示すものだから進捗が0パーセントから100パーセント。なので0から1が設定範囲。
widget.valueが0から1以外の値をとるならつかえないから、
_curveAnimation = _controller.drive(CurveTween(curve: Curves.easeIn));
で生成したCurveTweenの値で確実に0から1の値を設定しましょうねってことだと理解。
で、今のところ、実際に監視している値ってアニメーションクラス把握していなくない?って思ったあなた。賢いです。
なのでトリガーがあります。
@override
void didUpdateWidget(oldWidget) {
super.didUpdateWidget(oldWidget);
_controller.animateTo(widget.value);
}
こやつがトリガーです。
_AnimatedProgressIndicatorStateは
AnimatedProgressIndicatorウィジェットのプロパティの変更を監視しています。
なので、プロパティ(インプットテキストなど)に変更が入るとコールされます。
なんでコールされるのかは、
class _AnimatedProgressIndicatorState extends State<AnimatedProgressIndicator>
って宣言しているのでAnimatedProgressIndicatorを監視すると言っているからです。
監視しているのはフレームワーク側なので我々はどうやって監視しているのか?まではわからんというか知りたきゃ裏までソース追うしかないです。
以上。
Discussion