Fade a Widget in and out
As UI developers, we often need to show and hide elements on screen. However, quickly popping elements on and off the screen can feel jarring to end users. Instead, we can fade elements in and out with an opacity animation to create a smooth experience.
In Flutter, we can achieve this task using the AnimatedOpacity
Widget.
Directions
- Show a box to fade in and out
- Define a
StatefulWidget
- Display a button that toggles the visibility
- Fade the box in and out
1. Create a box to fade in and out
First, we’ll need something to fade in and out! In this example, we’ll draw a green box on screen.
new Container(
width: 200.0,
height: 200.0,
color: Colors.green,
);
2. Define a StatefulWidget
Now that we have a green box to animate, we’ll need a way to know whether the
box should be visible or invisible. To accomplish this, we can use a
StatefulWidget
.
A StatefulWidget
is a class that creates a State
object. The State
object
holds some data about our app and provides a way to update that data. When we
update the data, we can also ask Flutter to rebuild our UI with those changes.
In our case, we’ll have one piece of data: a boolean representing whether the button is visible or invisible.
To construct a StatefulWidget
, we need to create two classes: A
StatefulWidget
and a corresponding State
class. Pro tip: The Flutter plugins
for Android Studio and VSCode include the stful
snippet to quickly generate
this code!
// The StatefulWidget's job is to take in some data and create a State class.
// In this case, our Widget takes in a title, and creates a _MyHomePageState.
class MyHomePage extends StatefulWidget {
final String title;
MyHomePage({Key key, this.title}) : super(key: key);
@override
_MyHomePageState createState() => new _MyHomePageState();
}
// The State class is responsible for two things: holding some data we can
// update and building the UI using that data.
class _MyHomePageState extends State<MyHomePage> {
// Whether the green box should be visible or invisible
bool _visible = true;
@override
Widget build(BuildContext context) {
// The green box will go here with some other Widgets!
}
}
3. Display a button that toggles the visibility
Now that we have some data to determine whether our green box should be visible or invisible, we’ll need a way update that data. In our case, if the box is visible, we want to hide it. If the box is hidden, we want to show it!
To achieve this, we’ll display a button. When a user presses the button, we’ll
flip the boolean from true to false, or false to true. We need to make this
change using setState
,
which is a method on the State
class. This will let Flutter know it needs to
rebuild the Widget.
Note: For more information on working with user input, please see the Handling Gestures section of the Cookbook.
new FloatingActionButton(
onPressed: () {
// Make sure we call setState! This will tell Flutter to rebuild the
// UI with our changes!
setState(() {
_visible = !_visible;
});
},
tooltip: 'Toggle Opacity',
child: new Icon(Icons.flip),
);
4. Fade the box in and out
We’ve got a green box on screen. We’ve got a button to toggle the visibility
to true
or false
. So how do we fade the box in and out? With an
AnimatedOpacity
Widget!
The AnimatedOpacity
Widget requires three arguments:
opacity
: A value from 0.0 (invisible) to 1.0 (fully visible).duration
: How long the animation should take to completechild
: The Widget to animate. In our case, the green box.
new AnimatedOpacity(
// If the Widget should be visible, animate to 1.0 (fully visible). If
// the Widget should be hidden, animate to 0.0 (invisible).
opacity: _visible ? 1.0 : 0.0,
duration: new Duration(milliseconds: 500),
// The green box needs to be the child of the AnimatedOpacity
child: new Container(
width: 200.0,
height: 200.0,
color: Colors.green,
),
);
Complete Example
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
final appTitle = 'Opacity Demo';
return new MaterialApp(
title: appTitle,
home: new MyHomePage(title: appTitle),
);
}
}
// The StatefulWidget's job is to take in some data and create a State class.
// In this case, our Widget takes in a title, and creates a _MyHomePageState.
class MyHomePage extends StatefulWidget {
final String title;
MyHomePage({Key key, this.title}) : super(key: key);
@override
_MyHomePageState createState() => new _MyHomePageState();
}
// The State class is responsible for two things: holding some data we can
// update and building the UI using that data.
class _MyHomePageState extends State<MyHomePage> {
// Whether the green box should be visible or invisible
bool _visible = true;
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text(widget.title),
),
body: new Center(
child: new AnimatedOpacity(
// If the Widget should be visible, animate to 1.0 (fully visible). If
// the Widget should be hidden, animate to 0.0 (invisible).
opacity: _visible ? 1.0 : 0.0,
duration: new Duration(milliseconds: 500),
// The green box needs to be the child of the AnimatedOpacity
child: new Container(
width: 200.0,
height: 200.0,
color: Colors.green,
),
),
),
floatingActionButton: new FloatingActionButton(
onPressed: () {
// Make sure we call setState! This will tell Flutter to rebuild the
// UI with our changes!
setState(() {
_visible = !_visible;
});
},
tooltip: 'Toggle Opacity',
child: new Icon(Icons.flip),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}