Flutter: アニメーションのウィジェットを使ってみる
June 6, 2024
Flutter でアニメーションをするにはいろいろな方法がある。こちらの記事がわかりやすい。
- Flutter のお手軽にアニメーションを扱える Animated 系 Widget をすべて紹介 | by mono | Medium
- https://medium.com/flutter-jp/implicit-animation-b9d4b7358c28
上記記事中でも紹介されているが以下の動画が良き。
- Animations with Flutter: When to Use What - YouTube
- https://www.youtube.com/watch?v=PFKg_woOJmI
私なりにアニメーションを使ってみたのがこのような感じ。
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({
super.key,
});
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
@override
Widget build(BuildContext context) {
return const AnimatedColorWidget(
child: MaterialApp(
home: Center(
child: MyWidget(),
),
),
);
}
}
class MyWidget extends StatelessWidget {
const MyWidget({
super.key,
});
@override
Widget build(BuildContext context) {
final animatedColor = AnimatedColorWidget.of(context);
return ColoredBox(
color: animatedColor.color,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
IconButton(
onPressed: animatedColor.toLightMode,
icon: const Icon(Icons.light_mode),
),
IconButton(
onPressed: animatedColor.toDarkMode,
icon: const Icon(Icons.dark_mode),
),
],
),
);
}
}
class InheritedColorWidget extends InheritedWidget {
const InheritedColorWidget({
super.key,
required this.data,
required super.child,
});
final AnimatedColorWidgetState data;
@override
bool updateShouldNotify(InheritedColorWidget oldWidget) {
return data != oldWidget.data;
}
}
class AnimatedColorWidget extends ImplicitlyAnimatedWidget {
const AnimatedColorWidget({
super.key,
required this.child,
}) : super(
duration: const Duration(microseconds: 1000),
);
final Widget child;
static AnimatedColorWidgetState of(
BuildContext context, {
bool listen = true,
}) {
final result = listen
? context.dependOnInheritedWidgetOfExactType<InheritedColorWidget>()
: context
.getElementForInheritedWidgetOfExactType<InheritedColorWidget>()
?.widget as InheritedColorWidget?;
assert(result != null, 'No InheritedColorWidget found in context');
return result!.data;
}
@override
AnimatedColorWidgetState createState() => AnimatedColorWidgetState();
}
class AnimatedColorWidgetState
extends AnimatedWidgetBaseState<AnimatedColorWidget> {
Color _targetColor = Colors.white;
Tween<Color>? _tweenColor = Tween<Color>(begin: Colors.white);
Color get color => _tweenColor!.evaluate(animation);
void toLightMode() {
setState(() {
_targetColor = Colors.white;
});
}
void toDarkMode() {
setState(() {
_targetColor = Colors.black;
});
}
@override
void forEachTween(TweenVisitor<dynamic> visitor) {
_tweenColor = visitor(
_tweenColor,
_targetColor,
(dynamic value) => Tween<Color>(begin: value as Color?),
) as Tween<Color>?;
}
@override
Widget build(BuildContext context) => InheritedColorWidget(
data: AnimatedColorWidgetState(),
child: widget.child,
);
}