Flutter

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:

Flutter - AnimatedSwitcher

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:

Flutter - AnimatedSwitcher - reverseDuration

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:

Flutter - AnimatedSwitcher - curves

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:

Flutter - AnimatedSwitcher - transitionBuilder

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:

Flutter - AnimatedSwitcher - layoutBuilder

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 to Curves.linear.
  • Curve switchOutCurve: The animation curve to use when transitioning a previous child out. Defaults to Curves.linear.
  • AnimatedSwitcherTransitionBuilder transitionBuilder: A function that wraps the child with an animation. Defaults to AnimatedSwitcher.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 to AnimatedSwitcher.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.