I want to make an animated button that changes its child widget by animating. I did make the animation and I did change the widget by animating but my problem is that it does not update the widget on time, you should call it once again to show the last changes! I did try setState but it doesn't work. This is my animation class:
typedef LoadingStatusCallback = void Function(bool isLoading);
class AMASOpacityAndScale extends StatefulWidget {
const AMASOpacityAndScale(
{super.key,
required this.animationDurationInMiliSec,
required this.child,
required this.loadingStatusCallback});
final int animationDurationInMiliSec;
final Widget child;
final LoadingStatusCallback loadingStatusCallback;
@override
State<AMASOpacityAndScale> createState() => _AMASOpacityAndScaleState();
}
class _AMASOpacityAndScaleState extends State<AMASOpacityAndScale>
with TickerProviderStateMixin {
// variable initialization
late final AnimationController _controller = AnimationController(
vsync: this,
duration: Duration(milliseconds: widget.animationDurationInMiliSec));
final Curve _curve = Curves.easeIn;
late final Animation<double> _animation =
CurvedAnimation(curve: _curve, parent: _controller);
// for loading option
bool _isLoading = false;
// functions
void _animate() async {
await _controller.reverse().then((value) async {
_isLoading = !_isLoading;
widget.loadingStatusCallback(_isLoading);
await _controller.forward();
});
}
@override
void didUpdateWidget(covariant AMASOpacityAndScale oldWidget) {
_animate();
super.didUpdateWidget(oldWidget);
}
@override
void initState() {
_controller.forward();
super.initState();
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: _animation,
builder: (context, child) => Opacity(
opacity: _controller.value,
child: ScaleTransition(
scale: _animation,
child: widget.child,
)),
);
}
}
when _animate will be invoked, the loading which is a bool will be changed and callback the parent to change the widget to another (Changing the Text widget to CircularProgressIndicator widget). And the problem is exactly here! The Text does not turn to CircularProgress at first time you should call this _animate function again to change it to CircularProgress and vice versa!
This is part of my code that is related to the animation and the button:
AMASOpacityAndScale(
animationDurationInMiliSec: 200,
loadingStatusCallback: (isLoading) => {
print(_LocalVariables.isLoading),
_LocalVariables.isLoading = isLoading,
debugPrint("This is from amas btn: $isLoading"),
print(_LocalVariables.isLoading)
},
child: !_LocalVariables.isLoading
? Text(
text ?? 'AMASButton',
style: TextStyle(
color: textColor ??
(gradientBackgroundColor == null &&
!hasOutLines
? Colors.white
: Colors.black),
fontSize: fontSize,
fontFamily: fontFamily,
fontWeight: fontWeight),
)
: SizedBox(
height: height != null
? (height! - height! / 2.2)
: 50 - 22,
width: height != null
? (height! - height! / 2.2)
: 50 - 50 / 2.2,
child: CircularProgressIndicator(
strokeWidth: 2,
color: textColor ?? Colors.white,
),
))
class _LocalVariables {
static bool isLoading = false;
}
I added the button to another class which is a stateless class and added my local variables to another class to make the button class const. I did check stateful class too but it did not work. How can I change the Text to CircularProgress with only one invocation?
Thank you for help