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 {
late Widget _animatedModalBarrier;
late AnimationController _animationController;
late 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;
late Widget _animatedModalBarrier;
late AnimationController _animationController;
late 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: