6.2 KiB
6.2 KiB
| name | description |
|---|---|
| features-explicit-animations | Flutter explicit animations - AnimationController, Tween, AnimationBuilder, and custom animations |
Explicit Animations
Explicit animations give you full control over animation timing, curves, and values.
AnimationController
Control animation playback and timing.
class AnimatedWidget extends StatefulWidget {
const AnimatedWidget({super.key});
@override
State<AnimatedWidget> createState() => _AnimatedWidgetState();
}
class _AnimatedWidgetState extends State<AnimatedWidget>
with SingleTickerProviderStateMixin {
late AnimationController _controller;
@override
void initState() {
super.initState();
_controller = AnimationController(
duration: const Duration(seconds: 2),
vsync: this,
);
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Column(
children: [
ElevatedButton(
onPressed: () => _controller.forward(),
child: const Text('Start'),
),
ElevatedButton(
onPressed: () => _controller.reverse(),
child: const Text('Reverse'),
),
ElevatedButton(
onPressed: () => _controller.reset(),
child: const Text('Reset'),
),
],
);
}
}
Tween
Define animation value range.
final animation = Tween<double>(
begin: 0.0,
end: 1.0,
).animate(_controller);
// Different types
final colorAnimation = ColorTween(
begin: Colors.red,
end: Colors.blue,
).animate(_controller);
final sizeAnimation = Tween<double>(
begin: 50.0,
end: 200.0,
).animate(_controller);
final offsetAnimation = Tween<Offset>(
begin: Offset.zero,
end: Offset(100, 100),
).animate(_controller);
AnimationBuilder
Rebuild widget when animation value changes.
AnimationBuilder(
animation: _controller,
builder: (context, child) {
return Transform.scale(
scale: _controller.value,
child: Container(
width: 100,
height: 100,
color: Colors.blue,
),
);
},
)
// With Tween
AnimationBuilder(
animation: Tween<double>(begin: 0, end: 1).animate(_controller),
builder: (context, child) {
return Opacity(
opacity: Tween<double>(begin: 0, end: 1).animate(_controller).value,
child: Container(...),
);
},
)
CurvedAnimation
Apply curves to animations.
final curvedAnimation = CurvedAnimation(
parent: _controller,
curve: Curves.easeInOut,
reverseCurve: Curves.easeOut,
);
// Common curves
curve: Curves.linear
curve: Curves.easeIn
curve: Curves.easeOut
curve: Curves.easeInOut
curve: Curves.bounceIn
curve: Curves.bounceOut
curve: Curves.elasticIn
curve: Curves.elasticOut
Animation Status Listeners
Listen to animation state changes.
_controller.addStatusListener((status) {
if (status == AnimationStatus.completed) {
// Animation completed
} else if (status == AnimationStatus.dismissed) {
// Animation dismissed
} else if (status == AnimationStatus.forward) {
// Animation playing forward
} else if (status == AnimationStatus.reverse) {
// Animation playing reverse
}
});
_controller.addListener(() {
setState(() {
// Rebuild when animation value changes
});
});
Complete Example
class FadeScaleAnimation extends StatefulWidget {
const FadeScaleAnimation({super.key});
@override
State<FadeScaleAnimation> createState() => _FadeScaleAnimationState();
}
class _FadeScaleAnimationState extends State<FadeScaleAnimation>
with SingleTickerProviderStateMixin {
late AnimationController _controller;
late Animation<double> _fadeAnimation;
late Animation<double> _scaleAnimation;
@override
void initState() {
super.initState();
_controller = AnimationController(
duration: const Duration(milliseconds: 500),
vsync: this,
);
_fadeAnimation = Tween<double>(begin: 0.0, end: 1.0).animate(
CurvedAnimation(parent: _controller, curve: Curves.easeIn),
);
_scaleAnimation = Tween<double>(begin: 0.5, end: 1.0).animate(
CurvedAnimation(parent: _controller, curve: Curves.elasticOut),
);
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Column(
children: [
AnimationBuilder(
animation: _controller,
builder: (context, child) {
return Opacity(
opacity: _fadeAnimation.value,
child: Transform.scale(
scale: _scaleAnimation.value,
child: Container(
width: 100,
height: 100,
color: Colors.blue,
),
),
);
},
),
ElevatedButton(
onPressed: () {
if (_controller.isCompleted) {
_controller.reverse();
} else {
_controller.forward();
}
},
child: const Text('Animate'),
),
],
);
}
}
AnimationController Methods
// Start animation
_controller.forward(); // 0.0 to 1.0
_controller.reverse(); // 1.0 to 0.0
// Control animation
_controller.reset(); // Reset to 0.0
_controller.stop(); // Stop at current value
_controller.repeat(); // Repeat indefinitely
// Check status
_controller.isAnimating
_controller.isCompleted
_controller.isDismissed
// Get value
_controller.value // Current animation value (0.0 to 1.0)
Key Points
- Use
AnimationControllerto control animation timing - Use
Tweento define value ranges - Use
AnimationBuilderto rebuild widgets during animation - Use
CurvedAnimationfor custom timing curves - Implement
TickerProviderStateMixinfor single animation - Implement
TickerProviderfor multiple animations - Always dispose
AnimationControllerto prevent leaks - Use
addStatusListenerto react to animation state changes - Use
addListenerto rebuild widgets during animation