I'm unable to get the onEnd portion of AnimatedOpacity to get called.
I've got a _visible variable set to false, I'm changing that value with setState that is called on a button press, however the print statement in onEnd is never called.
Declared at the top of my widget and set to false initially.
bool _visible = false;
setState is updating visible from a textbutton onPressed
setState(() {
_visible = !_visible;
});
The visibility widget is toggled once the above state is passed however the container that is the child of the AnimatedOpacity widget is immediately shown ( there is no animated fade out from opacity to solid black ), and the only way to trigger the animation completely is to modify the _visible ? 1.0 : 0.0.
The goal is to get the container once triggered to change from an opacity of 0 to 1 then call onEnd, which currently is not happening.
Visibility(
visible: _visible,
child: Center(
child: AnimatedOpacity(
opacity: _visibility ? 1.0 : 0.0,
duration: const Duration(milliseconds: 1000),
onEnd: () {
print("I am never called");
},
child: Container(
width: double.infinity,
height: double.infinity,
color: Colors.black,
),
),
),
),
import 'package:flutter/material.dart';
class MyWidget extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return _MyWidgetState();
}
}
class _MyWidgetState extends State<MyWidget> {
bool _visible = false;
@override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomInset: false,
body: Stack(children: [
TextButton(
style: ElevatedButton.styleFrom(
elevation: 10,
shape: CircleBorder(),
primary: Colors.transparent,
onSurface: Colors.transparent,
shadowColor: Colors.transparent,
),
onPressed: () {
setState(() {
_visible = !_visible;
});
},
child: Icon(Icons.home, color: Colors.white),
),
Visibility(
visible: _visible,
child: Center(
child: AnimatedOpacity(
opacity: _visible ? 1 : 0,
duration: const Duration(milliseconds: 1000),
onEnd: () {
print("I am not called but should be");
},
child: Container(
width: 200,
height: 200,
color: Colors.black,
),
),
),
),
]));
}
}
CodePudding user response:
The problem with you code is that the AnimatedOpacity
widget is wrapped inside a Visibility
widget, which is not animated. Therefore when you call setState
to toggle _visible
member, the container will become instantly visible. The animation won't run at all, because by the time the Container
becomes visible, the _visible
member's value is already 1.
To solve this, simply remove Visibility
widget, when the AnimatedOpacity
reaches opacity
value of 0, the Container
will be invisible and on value 1 it will be visible, animating between the two states. The print
is also executed in onEnd
:
class MyWidget extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return _MyWidgetState();
}
}
class _MyWidgetState extends State<MyWidget> {
bool _visible = false;
@override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomInset: false,
body: Stack(children: [
TextButton(
style: ElevatedButton.styleFrom(
elevation: 10,
shape: const CircleBorder(),
primary: Colors.transparent,
onSurface: Colors.transparent,
shadowColor: Colors.transparent,
),
onPressed: () {
setState(() {
_visible = !_visible;
});
},
child: const Icon(Icons.home, color: Colors.white),
),
Center(
child: AnimatedOpacity(
opacity: _visible ? 1 : 0,
duration: const Duration(milliseconds: 1000),
onEnd: () {
print("I am not called but should be");
},
child: Container(
width: 200,
height: 200,
color: Colors.black,
),
),
]));
}
}