Flutter - Using AnimatedModalBuilder Examples

This tutorial explains how to use AnimatedModalBarrier in Flutter.

AnimatedModalBarrier is a widget that disables interactions with the widgets behind itself. It's similar to non-animated ModalBarrier, but it allows you to set an Animation<Color>, so that you can create an animation effect when the barrier is being shown up.

Creating AnimatedModalBarrier

Here's the constructor of AnimatedModalBarrier.

  const AnimatedModalBarrier({
    Key key,
    Animation color,
    this.dismissible = true,
    this.semanticsLabel,
    this.barrierSemanticsDismissible,
  })

Though Flutter doesn't explicitly mark color with @required argument, the argument is actually required since you will get assertion error if you don't pass it. First you need to create an AnimationController. A TickerProvider is required for the vsync argument, so you need to have a State class that extends TickerProviderStateMixin.

Below is an example of how to create the animation. You can use ColorTween to define the color at the beginning and end. In the AnimationController, set the duration how long the animation will be played. To create the Animation<Color>, use the ColorTween's animate method and pass the controller as the argument. After that, pass the Animation<Color>, as the color argument of AnimatedModalBarrier.

  class _AnimatedModalBarrierAppState extends State<_AnimatedModalBarrierApp> with SingleTickerProviderStateMixin {
    Widget _animatedModalBarrier;
  
    AnimationController _animationController;
    Animation<Color> _colorTweenAnimation;
  
    @override
    void initState() {
      ColorTween  _colorTween = ColorTween(
        begin: Color.fromARGB(100, 255, 255, 255),
        end: Color.fromARGB(100, 127, 127, 127),
      );
  
      _animationController = AnimationController(
          vsync: this,
          duration: const Duration(seconds: 3)
      );
      _colorTweenAnimation = _colorTween.animate(_animationController);
  
      _animatedModalBarrier = AnimatedModalBarrier(
        color: _colorTweenAnimation
      );
  
      super.initState();
    }
  }

As AnimatedModalBarrier works by preventing the user to interact with the widgets between itself, the easiest implementation is by using a Stack and putting the widgets where the interactions will be disabled before the AnimatedModalBarrier. In the below example, interactions with the RaisedButton is disabled.

  Stack(
    alignment: AlignmentDirectional.center,
    children: <Widget>[
      RaisedButton(
        child: Text('Button')
      ),
      _animatedModalBarrier
    ],
  )

Full Code

Below is the full code for this tutorial. There's a button when it's clicked, it will change the value of a state variable _isLoading to true start the animation. The AnimatedModalBarrier is added to the stack only when the _isLoading is true. In this way, we can dynamically add or remove the barrier to the stack. At that state, you'll see how the animation is played and you won't be able to click on the button.

  import 'dart:async';
  import 'package:flutter/material.dart';
  
  void main() => runApp(MyApp());
  
  class MyApp extends StatelessWidget {
    @override
    Widget build(BuildContext context) {
      return MaterialApp(
        title: 'Flutter Tutorial by Woolha.com',
        home: _AnimatedModalBarrierApp(),
      );
    }
  }
  
  class _AnimatedModalBarrierApp extends StatefulWidget {
    @override
    State<StatefulWidget> createState() {
      return _AnimatedModalBarrierAppState();
    }
  }
  
  class _AnimatedModalBarrierAppState extends State<_AnimatedModalBarrierApp> with SingleTickerProviderStateMixin {
    bool _isLoading = false;
    Widget _animatedModalBarrier;
  
    AnimationController _animationController;
    Animation<Color> _colorTweenAnimation;
  
    @override
    void initState() {
      ColorTween  _colorTween = ColorTween(
        begin: Color.fromARGB(100, 255, 255, 255),
        end: Color.fromARGB(100, 127, 127, 127),
      );
  
      _animationController = AnimationController(
          vsync: this,
          duration: const Duration(seconds: 3)
      );
      _colorTweenAnimation = _colorTween.animate(_animationController);
  
      _animatedModalBarrier = AnimatedModalBarrier(
        color: _colorTweenAnimation,
        dismissible: true,
      );
  
      super.initState();
    }
  
    List<Widget> buildWidgetList(BuildContext context) {
      List<Widget> widgets = <Widget>[
        RaisedButton(
          child: Text('Button'),
          onPressed: () {
            setState(() {
              _isLoading = true;
            });
  
            _animationController.reset();
            _animationController.forward();
  
            Scaffold.of(context).showSnackBar(
              SnackBar(content: Text('Button is pressed'))
            );
  
            Future.delayed(const Duration(seconds: 5), () {
              setState(() {
                _isLoading = false;
              });
            });
          },
        ),
      ];
  
      if (_isLoading) {
        widgets.add(_animatedModalBarrier);
      }
  
      return widgets;
    }
  
    @override
    Widget build(BuildContext context) {
      return Scaffold(
        appBar: AppBar(
          title: Text('Woolha.com Flutter Tutorial'),
        ),
        body: Builder(
          builder: (context) => Center(
            child: Padding(
              padding: EdgeInsets.all(15.0),
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: <Widget>[
                  Container(
                    height: 100.0,
                    width: 250.0,
                    // alignment: FractionalOffset.center,
                    child: new Stack(
                      alignment: AlignmentDirectional.center,
                      children: buildWidgetList(context),
                    ),
                  ),
                ],
              ),
            ),
          ),
        ),
      );
    }
  }
  

Output:

Flutter - AnimatedModalBarrier