--- name: features-implicit-animations description: Flutter implicit animations - AnimatedContainer, AnimatedOpacity, AnimatedSize, and other implicit animation widgets --- # Implicit Animations Implicit animations automatically animate property changes. They're simpler to use than explicit animations but less flexible. ## AnimatedContainer Automatically animates changes to Container properties. ```dart class AnimatedContainerExample extends StatefulWidget { const AnimatedContainerExample({super.key}); @override State createState() => _AnimatedContainerExampleState(); } class _AnimatedContainerExampleState extends State { bool _expanded = false; @override Widget build(BuildContext context) { return GestureDetector( onTap: () { setState(() { _expanded = !_expanded; }); }, child: AnimatedContainer( duration: const Duration(milliseconds: 300), curve: Curves.easeInOut, width: _expanded ? 200 : 100, height: _expanded ? 200 : 100, decoration: BoxDecoration( color: _expanded ? Colors.blue : Colors.red, borderRadius: BorderRadius.circular(_expanded ? 20 : 10), ), child: Center( child: Text(_expanded ? 'Expanded' : 'Collapsed'), ), ), ); } } ``` ## AnimatedOpacity Animates opacity changes. ```dart class AnimatedOpacityExample extends StatefulWidget { const AnimatedOpacityExample({super.key}); @override State createState() => _AnimatedOpacityExampleState(); } class _AnimatedOpacityExampleState extends State { bool _visible = true; @override Widget build(BuildContext context) { return Column( children: [ AnimatedOpacity( opacity: _visible ? 1.0 : 0.0, duration: const Duration(milliseconds: 300), child: const FlutterLogo(size: 100), ), ElevatedButton( onPressed: () { setState(() { _visible = !_visible; }); }, child: Text(_visible ? 'Hide' : 'Show'), ), ], ); } } ``` ## AnimatedSize Animates size changes. ```dart class AnimatedSizeExample extends StatefulWidget { const AnimatedSizeExample({super.key}); @override State createState() => _AnimatedSizeExampleState(); } class _AnimatedSizeExampleState extends State { bool _expanded = false; @override Widget build(BuildContext context) { return Column( children: [ AnimatedSize( duration: const Duration(milliseconds: 300), curve: Curves.easeInOut, child: Container( width: _expanded ? 200 : 100, height: _expanded ? 200 : 100, color: Colors.blue, child: _expanded ? const Center(child: Text('Expanded')) : const Center(child: Text('Small')), ), ), ElevatedButton( onPressed: () { setState(() { _expanded = !_expanded; }); }, child: Text(_expanded ? 'Collapse' : 'Expand'), ), ], ); } } ``` ## AnimatedCrossFade Cross-fades between two children. ```dart class AnimatedCrossFadeExample extends StatefulWidget { const AnimatedCrossFadeExample({super.key}); @override State createState() => _AnimatedCrossFadeExampleState(); } class _AnimatedCrossFadeExampleState extends State { bool _showFirst = true; @override Widget build(BuildContext context) { return Column( children: [ AnimatedCrossFade( duration: const Duration(milliseconds: 300), firstChild: Container( width: 200, height: 200, color: Colors.red, child: const Center(child: Text('First')), ), secondChild: Container( width: 200, height: 200, color: Colors.blue, child: const Center(child: Text('Second')), ), crossFadeState: _showFirst ? CrossFadeState.showFirst : CrossFadeState.showSecond, ), ElevatedButton( onPressed: () { setState(() { _showFirst = !_showFirst; }); }, child: const Text('Toggle'), ), ], ); } } ``` ## AnimatedSwitcher Switches between children with a transition. ```dart class AnimatedSwitcherExample extends StatefulWidget { const AnimatedSwitcherExample({super.key}); @override State createState() => _AnimatedSwitcherExampleState(); } class _AnimatedSwitcherExampleState extends State { int _counter = 0; @override Widget build(BuildContext context) { return Column( children: [ AnimatedSwitcher( duration: const Duration(milliseconds: 300), transitionBuilder: (child, animation) { return ScaleTransition( scale: animation, child: child, ); }, child: Text( '$_counter', key: ValueKey(_counter), style: const TextStyle(fontSize: 48), ), ), ElevatedButton( onPressed: () { setState(() { _counter++; }); }, child: const Text('Increment'), ), ], ); } } ``` ## AnimatedPositioned Animates position changes within a Stack. ```dart class AnimatedPositionedExample extends StatefulWidget { const AnimatedPositionedExample({super.key}); @override State createState() => _AnimatedPositionedExampleState(); } class _AnimatedPositionedExampleState extends State { bool _moved = false; @override Widget build(BuildContext context) { return Stack( children: [ AnimatedPositioned( duration: const Duration(milliseconds: 300), left: _moved ? 200 : 0, top: _moved ? 200 : 0, child: Container( width: 100, height: 100, color: Colors.blue, ), ), Positioned( bottom: 20, left: 20, child: ElevatedButton( onPressed: () { setState(() { _moved = !_moved; }); }, child: const Text('Move'), ), ), ], ); } } ``` ## Animation Curves Use curves to control animation timing. ```dart AnimatedContainer( duration: const Duration(milliseconds: 300), curve: Curves.easeInOut, // Common curves: linear, easeIn, easeOut, easeInOut, bounce, elastic // ... properties ) ``` ## Key Points - Implicit animations automatically animate property changes - Use `AnimatedContainer` for animating container properties - Use `AnimatedOpacity` for fade in/out effects - Use `AnimatedSize` for size changes - Use `AnimatedCrossFade` to transition between two widgets - Use `AnimatedSwitcher` to switch between children - Use `AnimatedPositioned` for position animations in Stack - Specify `duration` and `curve` for timing control - Implicit animations are simpler but less flexible than explicit animations