💫 Update the animation of alert's dialog

This commit is contained in:
2025-11-22 19:18:42 +08:00
parent f02b4abf65
commit 77b2effb34

View File

@@ -39,36 +39,51 @@ OverlayEntry? _loadingOverlay;
GlobalKey<_FadeOverlayState> _loadingOverlayKey = GlobalKey(); GlobalKey<_FadeOverlayState> _loadingOverlayKey = GlobalKey();
class _FadeOverlay extends StatefulWidget { class _FadeOverlay extends StatefulWidget {
const _FadeOverlay({super.key, required this.child}); const _FadeOverlay({
final Widget child; super.key,
this.child,
this.builder,
this.duration = const Duration(milliseconds: 200),
this.curve = Curves.linear,
}) : assert(child != null || builder != null);
final Widget? child;
final Widget Function(BuildContext, Animation<double>)? builder;
final Duration duration;
final Curve curve;
@override @override
State<_FadeOverlay> createState() => _FadeOverlayState(); State<_FadeOverlay> createState() => _FadeOverlayState();
} }
class _FadeOverlayState extends State<_FadeOverlay> { class _FadeOverlayState extends State<_FadeOverlay>
bool _visible = false; with SingleTickerProviderStateMixin {
late AnimationController _controller;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) { _controller = AnimationController(vsync: this, duration: widget.duration);
setState(() => _visible = true); _controller.forward();
}); }
@override
void dispose() {
_controller.dispose();
super.dispose();
} }
Future<void> animateOut() async { Future<void> animateOut() async {
setState(() => _visible = false); await _controller.reverse();
await Future.delayed(const Duration(milliseconds: 200));
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return AnimatedOpacity( final animation = CurvedAnimation(parent: _controller, curve: widget.curve);
opacity: _visible ? 1.0 : 0.0, if (widget.builder != null) {
duration: const Duration(milliseconds: 200), return widget.builder!(context, animation);
child: widget.child, }
); return FadeTransition(opacity: animation, child: widget.child);
} }
} }
@@ -166,18 +181,36 @@ Future<T?> showOverlayDialog<T>({
builder: builder:
(context) => _FadeOverlay( (context) => _FadeOverlay(
key: key, key: key,
child: Stack( duration: const Duration(milliseconds: 150),
curve: Curves.easeOut,
builder: (context, animation) {
return Stack(
children: [ children: [
Positioned.fill( Positioned.fill(
child: FadeTransition(
opacity: animation,
child: GestureDetector( child: GestureDetector(
onTap: barrierDismissible ? () => close(null) : null, onTap: barrierDismissible ? () => close(null) : null,
behavior: HitTestBehavior.opaque, behavior: HitTestBehavior.opaque,
child: const ColoredBox(color: Colors.black54), child: const ColoredBox(color: Colors.black54),
), ),
), ),
Center(child: builder(context, close)),
],
), ),
Center(
child: SlideTransition(
position: Tween<Offset>(
begin: const Offset(0, 0.05),
end: Offset.zero,
).animate(animation),
child: FadeTransition(
opacity: animation,
child: builder(context, close),
),
),
),
],
);
},
), ),
); );