import 'package:flutter/material.dart'; class Toast { static ToastView preToast; static void show(BuildContext context, String msg, int seconds, String toastType) { var overlayState = Overlay.of(context); var controllerShowAnim = AnimationController( vsync: overlayState, duration: Duration(milliseconds: 250), ); var controllerShowOffset = AnimationController( vsync: overlayState, duration: Duration(milliseconds: 350), ); var controllerHide = AnimationController( vsync: overlayState, duration: Duration(milliseconds: 250), ); var opacityAnim1 = Tween(begin: 0.0, end: 1.0).animate(controllerShowAnim); var controllerCurvedShowOffset = CurvedAnimation(parent: controllerShowOffset, curve: _BounceOutCurve._()); var offsetAnim = Tween(begin: 30.0, end: 0.0).animate(controllerCurvedShowOffset); var opacityAnim2 = Tween(begin: 1.0, end: 0.0).animate(controllerHide); OverlayEntry overlayEntry; overlayEntry = OverlayEntry(builder: (context) { return ToastWidget( opacityAnim1: opacityAnim1, opacityAnim2: opacityAnim2, offsetAnim: offsetAnim, child: buildToastLayout(msg, toastType), ); }); var toastView = ToastView(); if (seconds != null) { toastView.seconds = seconds; } toastView.overlayEntry = overlayEntry; toastView.controllerShowAnim = controllerShowAnim; toastView.controllerShowOffset = controllerShowOffset; toastView.controllerHide = controllerHide; toastView.overlayState = overlayState; preToast = toastView; toastView._show(); } static void hide() { if (preToast != null) { preToast.dismiss(); preToast = null; } } static LayoutBuilder buildToastLayout(String msg, String toastType) { return LayoutBuilder(builder: (context, constraints) { return Container( color: Colors.white.withOpacity(0), child: IgnorePointer( ignoring: true, child: Container( child: Material( color: Colors.white.withOpacity(0), child: Container( margin: EdgeInsets.only(top: toastType == 'num' ? 0 : 0), padding: EdgeInsets.symmetric(horizontal: toastType == 'info' ? 15 : (toastType == 'num' ? 0 : 36)), height: toastType == 'info' ? 40 : (toastType == 'num' ? 60 : 100), width: toastType == 'num' ? 60 : null, decoration: ShapeDecoration( color: Colors.black.withOpacity(toastType == 'num' ? 0.8 : 0.4), shape: RoundedRectangleBorder( borderRadius: BorderRadius.all( Radius.circular(toastType == 'num' ? 60 : 8.0), ), ), ), child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: _contentWidget(toastType, msg), ), )), alignment: Alignment.center, ), ), ); }); } } List _contentWidget(toastType, msg) { List widgetList = []; if (toastType == 'loading') { widgetList = [ CircularProgressIndicator(), Padding( padding: const EdgeInsets.only( top: 20.0, ), child: Text( msg, style: TextStyle(fontSize: 14.0, color: Colors.white), ), ), ]; } else if (toastType == 'success') { widgetList = [ Icon(Icons.done, color: Colors.green, size: 50), Padding( padding: const EdgeInsets.only( top: 10.0, ), child: Text( msg, style: TextStyle(fontSize: 14.0, color: Colors.white), ), ), ]; } else if (toastType == 'num') { widgetList = [ Text( msg, style: TextStyle(fontSize: 24.0, color: Colors.white), ), ]; } else { widgetList = [ Text( msg, style: TextStyle(fontSize: 14.0, color: Colors.white), ), ]; } return widgetList; } class ToastView { OverlayEntry overlayEntry; AnimationController controllerShowAnim; AnimationController controllerShowOffset; AnimationController controllerHide; OverlayState overlayState; bool dismissed = false; int seconds = 3500; Future _show() async { overlayState.insert(overlayEntry); controllerShowAnim.forward(); controllerShowOffset.forward(); if (seconds != -1) { await Future.delayed(Duration(milliseconds: seconds)); this.dismiss(); } } Future dismiss() async { if (dismissed) { return; } this.dismissed = true; controllerHide.forward(); await Future.delayed(Duration(milliseconds: 250)); overlayEntry?.remove(); } } class ToastWidget extends StatelessWidget { final Widget child; final Animation opacityAnim1; final Animation opacityAnim2; final Animation offsetAnim; ToastWidget({this.child, this.offsetAnim, this.opacityAnim1, this.opacityAnim2}); @override Widget build(BuildContext context) { return AnimatedBuilder( animation: opacityAnim1, child: child, builder: (context, child_to_build) { return Opacity( opacity: opacityAnim1.value, child: AnimatedBuilder( animation: offsetAnim, builder: (context, _) { return Transform.translate( offset: Offset(0, offsetAnim.value), child: AnimatedBuilder( animation: opacityAnim2, builder: (context, _) { return Opacity( opacity: opacityAnim2.value, child: child_to_build, ); }, ), ); }, ), ); }, ); } } class _BounceOutCurve extends Curve { const _BounceOutCurve._(); @override double transform(double t) { t -= 1.0; return t * t * ((2 + 1) * t + 2) + 1.0; } }