What is the Flutter AnimatedOpacity widget
The Flutter AnimatedOpacity
widget allows you to animate the opacity of a child widget. The opacity is the level of transparency of a widget. When the opacity is set to 1, the widget is fully visible, and when it is set to 0, the widget is fully transparent and not visible.
AnimatedOpacity takes two main arguments:
opacity
: The opacity you want to animate to. It’s a double value between 0 and 1.duration
: The duration of the animation. It’s aDuration
object that you can use to specify how long the animation should take.
When you use AnimatedOpacity, it animates the opacity of the child widget from its current value to the value you specify in the opacity
argument. For example, if you set opacity
to 0.5, the child widget will animate from its current opacity to 0.5 over the specified duration.
Here’s an example of how you could use AnimatedOpacity to animate the opacity of a container:
AnimatedOpacity(
duration: Duration(seconds: 1),
opacity: _visible ? 1.0 : 0.0,
child: Container(
width: 100,
height: 100,
color: Colors.red,
),
),
In the above example, when _visible
is true, the container’s opacity will animate from 0 to 1 over 1 second. When _visible is false, the container’s opacity will animate from 1 to 0 over 1 second.
It’s a simple way to add visual interest to your app and make it more engaging. It’s also a useful tool for creating animations that reveal or hide a widget, as it allows you to animate the widget’s visibility.
Where the Flutter AnimatedOpacity widget can be used
The AnimatedOpacity
widget can be used in various places within a Flutter app where you want to animate the transition of an element’s opacity. Here are a few examples of where you might use the AnimatedOpacity
widget:
- To create a button or other interactive element that fades in and out when tapped
- To create a loading animation that fades in and out
- To create a transition between different pages or screens in your app
- To animate the transition between different elements within a container or other layout widget
- To create an animation effect when displaying a dialogue or other overlay on the screen
- To create a transition effect for items in a list or other scrolling container
- To create an animation effect for images, text, or other widgets when the user interacts with them
The AnimatedOpacity
widget can be used in combination with other animation widgets such as AnimatedContainer
, AnimatedCrossFade
, AnimatedPositioned
and many others to create more complex and dynamic animations.
How to use the AnimatedOpacity widget in Flutter
Here’s an example of how you could create a button to toggle the visibility of an AnimatedOpacity widget:
bool _isVisible = true; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('flutterassets.com'), ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ AnimatedOpacity( duration: Duration(milliseconds: 500), opacity: _isVisible ? 1 : 0, child: Container( width: 100, height: 100, color: Colors.red, ), ), SizedBox(height: 10), ElevatedButton( onPressed: () { setState(() { _isVisible = !_isVisible; }); }, child: Text("Toggle Visibility"), ), ], ), ) ); }
In the code above, the AnimatedOpacity
is used to animate the visibility of a red Container
widget. The AnimatedOpacity
widget takes two main arguments, duration
and opacity
.
duration
is a Duration
object that specifies how long the animation should take. In this example, the duration is set to 500 milliseconds, which means the animation will take half a second to complete.
opacity
is a double value between 0 and 1 that represents the level of transparency of the child widget. If the opacity is set to 0, the widget is fully transparent and not visible. If the opacity is set to 1, the widget is fully visible. In this example, the opacity is controlled by the _isVisible
state variable. When _isVisible
is true
, the opacity is set to 1, making the Container
fully visible, and when _isVisible
is false
, the opacity is set to 0, making the Container
fully transparent.
The AnimatedOpacity
widget has only one child, which is the Container
widget. The Container
widget has a width and height of 100 pixels and a red colour.
The AnimatedOpacity
widget is wrapped in a Column
widget, which is centred on the screen using the Center
widget. The Column
widget contains the AnimatedOpacity
widget and a RaisedButton
widget. The RaisedButton
widget has a child
property of Text("Toggle Visibility")
and an onPressed
callback that toggles the value of _isVisible
between true
and false
when the button is pressed.
When the RaisedButton
is pressed, the onPressed
callback is executed, which calls the setState
function, which triggers the build
method to be executed again. As a result, the AnimatedOpacity
widget re-renders with the updated value of _isVisible
. If _isVisible
is now false
, the AnimatedOpacity
will animate the opacity of the Container
from 1 to 0 over the specified duration (500 milliseconds), making the container disappear gradually. If _isVisible
is now true
, the AnimatedOpacity
will animate the opacity of the Container
from 0 to 1 over the specified duration (500 milliseconds), making the container appear gradually. This allows the user to toggle the visibility of the container by tapping on the button.
Toggle two images with AnimatedOpacity in Flutter
Here’s an example of how you could use the AnimatedOpacity
widget to toggle the opacity of two Container
widgets with different decoration images, stacked one over the other, triggered by tapping on the containers:
bool _isContainer1Visible = true;
bool _isContainer2Visible = true;
@override
Widget build(BuildContext context) {
final screenHeight = MediaQuery.of(context).size.height;
final screenWidth = MediaQuery.of(context).size.width;
return Scaffold(
appBar: AppBar(
title: Text('flutterassets.com'),
),
body:
Center(
child: Stack(
children: <Widget>[
GestureDetector(
onTap: () {
setState(() {
_isContainer1Visible = !_isContainer1Visible;
});
},
child: AnimatedOpacity(
duration: Duration(milliseconds: 500),
opacity: _isContainer1Visible ? 1 : 0,
child: Container(
width: screenWidth/3,
height: screenHeight/3,
padding: EdgeInsets.all(6),
decoration: BoxDecoration(
image: DecorationImage(
image: NetworkImage("https://picsum.photos/250?image=9"),
fit: BoxFit.cover,
),
),
),
),
),
GestureDetector(
onTap: () {
setState(() {
_isContainer2Visible = !_isContainer2Visible;
});
},
child: AnimatedOpacity(
duration: Duration(milliseconds: 500),
opacity: _isContainer2Visible ? 1 : 0,
child: Container(
width: screenWidth/3,
height: screenHeight/3,
padding: EdgeInsets.all(6),
decoration: BoxDecoration(
image: DecorationImage(
image: NetworkImage("https://picsum.photos/250?image=10"),
fit: BoxFit.cover,
),
),
),
),
),
],
),
)
);
}
The above code uses the AnimatedOpacity widget to toggle the visibility of two Container widgets, stacked one over the other when the containers are tapped. The code defines a MyApp
class, which is a StatefulWidget
, and a corresponding _MyAppState
class, which is the state for the MyApp
widget.
The build
method of the _MyAppState
class is where the widgets are built and arranged on the screen. It starts by getting the screen height and width using MediaQuery.of(context).size.height
and MediaQuery.of(context).size.width
respectively. Then it returns a Scaffold
widget, which is the root of the app’s visual structure and it contains a Stack
widget. The Stack
widget allows you to position multiple widgets on top of each other.
Then, the code defines two GestureDetector
widgets, which are used to detect when the containers are tapped. The onTap
callback of each GestureDetector
toggles the visibility of the corresponding container by changing the value of _isContainer1Visible
and _isContainer2Visible
variables and calling setState
, which causes the widgets to rebuild and apply the new opacity value. Each GestureDetector
widget has an AnimatedOpacity
widget as a child.
The AnimatedOpacity
widget is used to animate the transition between different opacity values of the container. The duration
argument is set to 500 milliseconds, so the animation takes half a second to complete. The opacity
argument is controlled by the
You can rebuild the code above and use only one bool
variable to control the visibility of both containers. You can do this by using the bool
variable to determine which container should be visible, and then use the AnimatedOpacity
widget to animate the transition between the two containers.
Here’s an example of how you can modify the code to use only one bool
variable:
bool _isContainerVisible = false;
@override
Widget build(BuildContext context) {
final screenHeight = MediaQuery.of(context).size.height;
final screenWidth = MediaQuery.of(context).size.width;
return Scaffold(
appBar: AppBar(
title: Text('flutterassets.com'),
),
body:
Center(
child: GestureDetector(
onTap: () {
setState(() {
_isContainerVisible = !_isContainerVisible;
});
},
child: Stack(
children: <Widget>[
AnimatedOpacity(
duration: Duration(milliseconds: 500),
opacity: _isContainerVisible ? 0 : 1,
child: Container(
width: screenWidth / 3,
height: screenHeight / 3,
padding: EdgeInsets.all(6),
decoration: BoxDecoration(
image: DecorationImage(
image: NetworkImage("https://picsum.photos/250?image=9"),
fit: BoxFit.cover,
),
),
),
),
AnimatedOpacity(
duration: Duration(milliseconds: 500),
opacity: _isContainerVisible ? 1 : 0,
child: Container(
width: screenWidth / 3,
height: screenHeight / 3,
padding: EdgeInsets.all(6),
decoration: BoxDecoration(
image: DecorationImage(
image: NetworkImage("https://picsum.photos/250?image=10"),
fit: BoxFit.cover,
),
),
),
),
],
),
),
)
);
}
In this example, I removed the GestureDetector
widgets and wrapped the Stack
widget with a single GestureDetector
widget. The onTap
callback of the GestureDetector
toggles the value of the _isContainerVisible
variable and calls setState
, which causes the widgets to rebuild and apply the new opacity values.
The AnimatedOpacity
widgets use the _isContainerVisible
variable to determine the opacity value for each container. When _isContainerVisible
is false
, the first container has an opacity of 1 and the second container has an opacity of 0, so the first container is visible and the second one is not. When _isContainerVisible
is true
, the first container has an opacity of 0 and the second container has an opacity of 1, so the second container is visible and the first one is not.
As the user taps on the containers the _isContainerVisible
variable will toggle its value between true and false, which will make the containers to animate their opacity and change which one is visible. This way, the user can toggle the visibility of the two containers using only one variable.
Two image Toggle custom widget with AnimatedOpacity in Flutter
Here is an example of how you can create a custom StatelessWidget
class called MyImageOpacity
:
class MyImageOpacity extends StatelessWidget {
final String imageOne;
final String imageTwo;
final bool imageVisible;
final VoidCallback onPressed;
MyImageOpacity({
required this.imageOne,
required this.imageTwo,
required this.imageVisible,
required this.onPressed,
});
@override
Widget build(BuildContext context) {
final screenHeight = MediaQuery.of(context).size.height;
final screenWidth = MediaQuery.of(context).size.width;
return GestureDetector(
onTap: onPressed,
child: Stack(
children: <Widget>[
AnimatedOpacity(
duration: Duration(milliseconds: 500),
opacity: imageVisible ? 0 : 1,
child: Container(
width: screenWidth / 3,
height: screenHeight / 3,
decoration: BoxDecoration(
image: DecorationImage(
image: NetworkImage(imageOne),
fit: BoxFit.cover,
),
),
),
),
AnimatedOpacity(
duration: Duration(milliseconds: 500),
opacity: imageVisible ? 1 : 0,
child: Container(
width: screenWidth / 3,
height: screenHeight / 3,
decoration: BoxDecoration(
image: DecorationImage(
image: NetworkImage(imageTwo),
fit: BoxFit.cover,
),
),
),
),
],
),
);
}
}
The MyImageOpacity
class takes in three required properties: imageOne
, imageTwo
, and imageVisible
. The imageOne
and imageTwo
properties are used to set the URLs for the first and second network images, respectively. The imageVisible
property is a bool
value that determines which image is visible.
You can use the MyImageOpacity
class to create a row of 3 widgets by wrapping it in a Row
widget and passing different values to the properties. Here’s an example:
Row(
children: <Widget>[
MyImageOpacity(
imageOne: "https://picsum.photos/250?image=9",
imageTwo: "https://picsum.photos/250?image=10",
imageVisible: _isFirstVisible,
),
MyImageOpacity(
imageOne: "https://picsum.photos/250?image=11",
imageTwo: "https://picsum.photos/250?image=12",
imageVisible: _isSecondVisible,
),
MyImageOpacity(
imageOne: "https://picsum.photos/250?image=13",
imageTwo: "https://picsum.photos/250?image=14",
imageVisible: _
isThirdVisible,
),
],
)
In this example, I created 3 instances of the `MyImageOpacity` widget, each with its own set of image URLs and a separate `bool` variable to control the visibility of the images. The `Row` widget arranges the widgets horizontally on the screen.
It’s important to note that since the `MyImageOpacity` class is stateless, the `setState` method will not work in the `onTap` callback, it would need to be passed down from the parent widget, where the state is kept. The `imageVisible` variable would be passed as a callback function that updates the variable from the parent widget.
Creating a Row with Custom Image Toggling Widget in Flutter
Here is an example of how you can combine the two code examples to create a Flutter app that uses the custom MyImageOpacity
widget to create a row of 3 image containers that toggle their visibility when tapped:
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> with SingleTickerProviderStateMixin {
bool _isFirstVisible = true;
bool _isSecondVisible = true;
bool _isThirdVisible = true;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('flutterassets.com'),
),
body:
Center(
child: Row(
children: <Widget>[
MyImageOpacity(
imageOne: "https://picsum.photos/250?image=9",
imageTwo: "https://picsum.photos/250?image=10",
imageVisible: _isFirstVisible,
onPressed: () {
setState(() {
_isFirstVisible = !_isFirstVisible;
});
},
),
MyImageOpacity(
imageOne: "https://picsum.photos/250?image=11",
imageTwo: "https://picsum.photos/250?image=12",
imageVisible: _isSecondVisible,
onPressed: () {
setState(() {
_isSecondVisible = !_isSecondVisible;
});
},
),
MyImageOpacity(
imageOne: "https://picsum.photos/250?image=13",
imageTwo: "https://picsum.photos/250?image=14",
imageVisible: _isThirdVisible,
onPressed: () {
setState(() {
_isThirdVisible = !_isThirdVisible;
});
},
),
],
),
),
);
}
}
class MyImageOpacity extends StatelessWidget {
final String imageOne;
final String imageTwo;
final bool imageVisible;
final VoidCallback onPressed;
MyImageOpacity({
required this.imageOne,
required this.imageTwo,
required this.imageVisible,
required this.onPressed,
});
@override
Widget build(BuildContext context) {
final screenHeight = MediaQuery.of(context).size.height;
final screenWidth = MediaQuery.of(context).size.width;
return GestureDetector(
onTap: onPressed,
child: Stack(
children: <Widget>[
AnimatedOpacity(
duration: Duration(milliseconds: 500),
opacity: imageVisible ? 0 : 1,
child: Container(
width: screenWidth / 3,
height: screenHeight / 3,
decoration: BoxDecoration(
image: DecorationImage(
image: NetworkImage(imageOne),
fit: BoxFit.cover,
),
),
),
),
AnimatedOpacity(
duration: Duration(milliseconds: 500),
opacity: imageVisible ? 1 : 0,
child: Container(
width: screenWidth / 3,
height: screenHeight / 3,
decoration: BoxDecoration(
image: DecorationImage(
image: NetworkImage(imageTwo),
fit: BoxFit.cover,
),
),
),
),
],
),
);
}
}
The above code creates a Flutter app that has a custom widget called MyImageOpacity
. This widget takes in 3 properties: imageOne
, imageTwo
, and imageVisible
. imageOne
and imageTwo
are used to set the URLs for the first and second network images, respectively. imageVisible
is a boolean variable that determines which image is visible.
MyImageOpacity
widget uses AnimatedOpacity
to animate the transition between the two images, which makes the opacity of one image to change to 0 when the other image’s opacity is 1. The MyApp
class uses the MyImageOpacity
widget to create a row of 3 image containers. Each container has its own set of image URLs and its own imageVisible
variable to control the visibility of the images.
When user taps on any of the container the onPressed
callback is executed and the value of the respective imageVisible
variable is toggled. This causes the state to rebuild and the widgets to update the opacity accordingly. This way the user can toggle the visibility of the two images by tapping on the container.