This tutorial shows you how to use AnimatedSwitcher
widget in Flutter.
AnimatedSwitcher
is a widget that can be used for creating animation when switching between two widgets. When a widget is replaced with another, it transitions the new widget in and transitions the previous widget out. The examples of how to use the widget and do customizations can be found in this tutorial.
Using AnimatedSwitcher
Below is the constructor of AnimatedSwitcher
.
const AnimatedSwitcher({
Key key,
this.child,
@required this.duration,
this.reverseDuration,
this.switchInCurve = Curves.linear,
this.switchOutCurve = Curves.linear,
this.transitionBuilder = AnimatedSwitcher.defaultTransitionBuilder,
this.layoutBuilder = AnimatedSwitcher.defaultLayoutBuilder,
})
The only required argument is duration
. For that argument, you need to pass an instance of Duration
which is used to set how long the transition should be played.
The widget to be animated needs to be set as child
argument. When the widget is replaced with a new one, the animation will be played. If the replacing widget has the same type as the old one, you must set the key
property of each widget. Without that, the new widget will replace the old one without any animation. However, that's not necessary if the new widget's type is different.
In this tutorial, we are going to create a layout that consists of a widget wrapped as the child of AnimatedSwitcher
and a button to change the child widget.
class _AnimatedSwitcherExampleState extends State<_AnimatedSwitcherExample> {
int _widgetId = 1;
Widget _renderWidget1() {
return Container(
key: Key('first'),
width: 150,
height: 50,
color: Colors.teal,
child: const Center(
child: const Text(
'Woolha.com',
style: const TextStyle(fontSize: 24, color: Colors.white)
),
),
);
}
Widget _renderWidget2() {
return Container(
key: Key('second'),
width: 90,
height: 150,
color: Colors.red,
child: const Center(
child: const Text(
'Woolha.com',
style: const TextStyle(fontSize: 24, color: Colors.white)
),
),
);
}
Widget _renderWidget() {
return _widgetId == 1 ? _renderWidget1() : _renderWidget2();
}
void _updateWidget() {
setState(() {
_widgetId = _widgetId == 1 ? 2 : 1;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Woolha.com Flutter Tutorial'),
),
body: SizedBox(
width: double.infinity,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
AnimatedSwitcher(
duration: const Duration(seconds: 3),
child: _renderWidget(),
),
RaisedButton(
child: const Text('Change Widget'),
onPressed: () {
_updateWidget();
},
),
],
),
),
);
}
}
When the widget is replaced with another one, there are two transitions: transitioning the new child in and transitioning the previous child out. For example (using the code above), the currently displayed widget is the first widget. If the animation is triggered, it will start to create two transitions. During the animation, you will see that the first widget is being transitioned out, while the second widget is being transitioned in.
Output:
Set Reverse Duration
If you only pass the duration
argument, the given value will be used for transitioning the new widget in and transitioning the old widget out. If you want to set a different duration for transitioning the old widget out, you can pass reverseDuration
argument.
AnimatedSwitcher(
duration: const Duration(seconds: 3),
reverseDuration: const Duration(seconds: 1),
child: _renderWidget(),
)
Output:
Set Animation Curves
By default, the curves used for both transitions are linear. For transitioning the new widget in, you can set the animation curve by passing switchInCurve
argument. For transitioning the old widget out, the argument you need to pass is switchOutCurve
.
AnimatedSwitcher(
duration: const Duration(seconds: 3),
switchInCurve: Curves.bounceInOut,
switchOutCurve: Curves.easeOutCirc,
child: _renderWidget(),
)
Output:
Set Transition Builder
It uses FadeTransition
by default. To customize the animation, you can pass a function as transitionBuilder
argument. The passed function accepts two parameters and needs to return a Widget
.
Widget Function(Widget child, Animation<double> animation)
By doing so, you can set another type of transition such as ScaleTransition
.
AnimatedSwitcher(
duration: const Duration(seconds: 3),
transitionBuilder: (Widget child, Animation<double> animation) {
return ScaleTransition(scale: animation, child: child);
},
child: _renderWidget(),
)
Output:
Set Layout Builder
By default, the new child and the previous children are laid out as the children of Stack
widget. That means the Stack
widget is responsible to determine how the children are laid out. If you need to change how the children are laid out, you can pass a function as layoutBuilder
argument.
Widget defaultLayoutBuilder(Widget currentChild, List<Widget> previousChildren)
Below is the example that uses a Column
widget instead.
AnimatedSwitcher(
duration: const Duration(seconds: 3),
layoutBuilder: (Widget? currentChild, List<Widget> previousChildren) {
return Column(
children: <Widget>[
...previousChildren,
if (currentChild != null) currentChild,
],
);
},
child: _renderWidget(),
)
Output:
Parameters
Key key
: The widget's key, used to control how a widget is replaced with another widget.Widget child
: The widget under this widget in the tree.required Duration duration
: The duration of the animation.Duration reverseDuration
: The duration of the animation for transitioning the previous child out.Curve switchInCurve
: The animation curve to use when transitioning a new child in. Defaults toCurves.linear
.Curve switchOutCurve
: The animation curve to use when transitioning a previous child out. Defaults toCurves.linear
.AnimatedSwitcherTransitionBuilder transitionBuilder
: A function that wraps the child with an animation. Defaults toAnimatedSwitcher.defaultTransitionBuilder
.AnimatedSwitcherLayoutBuilder layoutBuilder
: A function that wraps all children (the transitioning out children and the transitioning in child) with a widget that lays all of them out. Defaults toAnimatedSwitcher.defaultLayoutBuilder
.
Full Code
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Woolha.com Flutter Tutorial',
home: _AnimatedSwitcherExample(),
);
}
}
class _AnimatedSwitcherExample extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return _AnimatedSwitcherExampleState();
}
}
class _AnimatedSwitcherExampleState extends State<_AnimatedSwitcherExample> {
int _widgetId = 1;
Widget _renderWidget1() {
return Container(
key: Key('first'),
width: 150,
height: 50,
color: Colors.teal,
child: const Center(
child: const Text(
'Woolha.com',
style: const TextStyle(fontSize: 24, color: Colors.white)
),
),
);
}
Widget _renderWidget2() {
return Container(
key: Key('second'),
width: 90,
height: 150,
color: Colors.red,
child: const Center(
child: const Text(
'Woolha.com',
style: const TextStyle(fontSize: 24, color: Colors.white)
),
),
);
}
Widget _renderWidget() {
return _widgetId == 1 ? _renderWidget1() : _renderWidget2();
}
void _updateWidget() {
setState(() {
_widgetId = _widgetId == 1 ? 2 : 1;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Woolha.com Flutter Tutorial'),
),
body: SizedBox(
width: double.infinity,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
AnimatedSwitcher(
duration: const Duration(seconds: 3),
reverseDuration: const Duration(seconds: 1),
switchInCurve: Curves.bounceInOut,
switchOutCurve: Curves.easeOutCirc,
transitionBuilder: (Widget child, Animation<double> animation) {
return ScaleTransition(scale: animation, child: child);
},
layoutBuilder: (Widget? currentChild, List<Widget> previousChildren) {
return Column(
children: <Widget>[
...previousChildren,
if (currentChild != null) currentChild,
],
);
},
child: _renderWidget(),
),
RaisedButton(
child: const Text('Change Widget'),
onPressed: () {
_updateWidget();
},
),
],
),
),
);
}
}
Summary
That's how to create animation when switching a widget with another one using AnimatedSwitcher
.
You can also read about other related widgets. Some of which are transition widgets which can be used for customizing the transition of AnimatedSwitcher
.
FadeTransition
, a widget that animates the opacity of its child widget.SlideTransition
, a widget for creating transition animation.RotationTransition
, a widget for creating rotation animation.ScaleTransition
, a widget for creating scale animation.AnimatedCrossFade
, a widget for creating fading effects when a widget is being replaced with another.AnimatedAlign
, a widget for creating animation when the alignment of a widget changes.AnimatedPadding
, a widget for creating animation when the padding of a widget changes.AnimatedOpacity
, a widget for creating animation when the opacity of a widget changes.AnimatedSize
, a widget that animates its size to match the size of its child.AnimatedContainer
, a widget that starts an animation when the value of a property changes.