totast.dart 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. import 'package:flutter/material.dart';
  2. class Toast {
  3. static ToastView preToast;
  4. static void show(BuildContext context, String msg, int seconds, String toastType) {
  5. var overlayState = Overlay.of(context);
  6. var controllerShowAnim = AnimationController(
  7. vsync: overlayState,
  8. duration: Duration(milliseconds: 250),
  9. );
  10. var controllerShowOffset = AnimationController(
  11. vsync: overlayState,
  12. duration: Duration(milliseconds: 350),
  13. );
  14. var controllerHide = AnimationController(
  15. vsync: overlayState,
  16. duration: Duration(milliseconds: 250),
  17. );
  18. var opacityAnim1 = Tween(begin: 0.0, end: 1.0).animate(controllerShowAnim);
  19. var controllerCurvedShowOffset = CurvedAnimation(parent: controllerShowOffset, curve: _BounceOutCurve._());
  20. var offsetAnim = Tween(begin: 30.0, end: 0.0).animate(controllerCurvedShowOffset);
  21. var opacityAnim2 = Tween(begin: 1.0, end: 0.0).animate(controllerHide);
  22. OverlayEntry overlayEntry;
  23. overlayEntry = OverlayEntry(builder: (context) {
  24. return ToastWidget(
  25. opacityAnim1: opacityAnim1,
  26. opacityAnim2: opacityAnim2,
  27. offsetAnim: offsetAnim,
  28. child: buildToastLayout(msg, toastType),
  29. );
  30. });
  31. var toastView = ToastView();
  32. if (seconds != null) {
  33. toastView.seconds = seconds;
  34. }
  35. toastView.overlayEntry = overlayEntry;
  36. toastView.controllerShowAnim = controllerShowAnim;
  37. toastView.controllerShowOffset = controllerShowOffset;
  38. toastView.controllerHide = controllerHide;
  39. toastView.overlayState = overlayState;
  40. preToast = toastView;
  41. toastView._show();
  42. }
  43. static void hide() {
  44. if (preToast != null) {
  45. preToast.dismiss();
  46. preToast = null;
  47. }
  48. }
  49. static LayoutBuilder buildToastLayout(String msg, String toastType) {
  50. return LayoutBuilder(builder: (context, constraints) {
  51. return Container(
  52. color: Colors.white.withOpacity(0),
  53. child: IgnorePointer(
  54. ignoring: true,
  55. child: Container(
  56. child: Material(
  57. color: Colors.white.withOpacity(0),
  58. child: Container(
  59. margin: EdgeInsets.only(top: toastType == 'num' ? 0 : 0),
  60. padding: EdgeInsets.symmetric(horizontal: toastType == 'info' ? 15 : (toastType == 'num' ? 0 : 36)),
  61. height: toastType == 'info' ? 40 : (toastType == 'num' ? 60 : 100),
  62. width: toastType == 'num' ? 60 : null,
  63. decoration: ShapeDecoration(
  64. color: Colors.black.withOpacity(toastType == 'num' ? 0.8 : 0.4),
  65. shape: RoundedRectangleBorder(
  66. borderRadius: BorderRadius.all(
  67. Radius.circular(toastType == 'num' ? 60 : 8.0),
  68. ),
  69. ),
  70. ),
  71. child: Column(
  72. mainAxisAlignment: MainAxisAlignment.center,
  73. crossAxisAlignment: CrossAxisAlignment.center,
  74. children: _contentWidget(toastType, msg),
  75. ),
  76. )),
  77. alignment: Alignment.center,
  78. ),
  79. ),
  80. );
  81. });
  82. }
  83. }
  84. List<Widget> _contentWidget(toastType, msg) {
  85. List<Widget> widgetList = [];
  86. if (toastType == 'loading') {
  87. widgetList = [
  88. CircularProgressIndicator(),
  89. Padding(
  90. padding: const EdgeInsets.only(
  91. top: 20.0,
  92. ),
  93. child: Text(
  94. msg,
  95. style: TextStyle(fontSize: 14.0, color: Colors.white),
  96. ),
  97. ),
  98. ];
  99. } else if (toastType == 'success') {
  100. widgetList = [
  101. Icon(Icons.done, color: Colors.green, size: 50),
  102. Padding(
  103. padding: const EdgeInsets.only(
  104. top: 10.0,
  105. ),
  106. child: Text(
  107. msg,
  108. style: TextStyle(fontSize: 14.0, color: Colors.white),
  109. ),
  110. ),
  111. ];
  112. } else if (toastType == 'num') {
  113. widgetList = [
  114. Text(
  115. msg,
  116. style: TextStyle(fontSize: 24.0, color: Colors.white),
  117. ),
  118. ];
  119. } else {
  120. widgetList = [
  121. Text(
  122. msg,
  123. style: TextStyle(fontSize: 14.0, color: Colors.white),
  124. ),
  125. ];
  126. }
  127. return widgetList;
  128. }
  129. class ToastView {
  130. OverlayEntry overlayEntry;
  131. AnimationController controllerShowAnim;
  132. AnimationController controllerShowOffset;
  133. AnimationController controllerHide;
  134. OverlayState overlayState;
  135. bool dismissed = false;
  136. int seconds = 3500;
  137. Future<void> _show() async {
  138. overlayState.insert(overlayEntry);
  139. controllerShowAnim.forward();
  140. controllerShowOffset.forward();
  141. if (seconds != -1) {
  142. await Future.delayed(Duration(milliseconds: seconds));
  143. this.dismiss();
  144. }
  145. }
  146. Future<void> dismiss() async {
  147. if (dismissed) {
  148. return;
  149. }
  150. this.dismissed = true;
  151. controllerHide.forward();
  152. await Future.delayed(Duration(milliseconds: 250));
  153. overlayEntry?.remove();
  154. }
  155. }
  156. class ToastWidget extends StatelessWidget {
  157. final Widget child;
  158. final Animation<double> opacityAnim1;
  159. final Animation<double> opacityAnim2;
  160. final Animation<double> offsetAnim;
  161. ToastWidget({this.child, this.offsetAnim, this.opacityAnim1, this.opacityAnim2});
  162. @override
  163. Widget build(BuildContext context) {
  164. return AnimatedBuilder(
  165. animation: opacityAnim1,
  166. child: child,
  167. builder: (context, child_to_build) {
  168. return Opacity(
  169. opacity: opacityAnim1.value,
  170. child: AnimatedBuilder(
  171. animation: offsetAnim,
  172. builder: (context, _) {
  173. return Transform.translate(
  174. offset: Offset(0, offsetAnim.value),
  175. child: AnimatedBuilder(
  176. animation: opacityAnim2,
  177. builder: (context, _) {
  178. return Opacity(
  179. opacity: opacityAnim2.value,
  180. child: child_to_build,
  181. );
  182. },
  183. ),
  184. );
  185. },
  186. ),
  187. );
  188. },
  189. );
  190. }
  191. }
  192. class _BounceOutCurve extends Curve {
  193. const _BounceOutCurve._();
  194. @override
  195. double transform(double t) {
  196. t -= 1.0;
  197. return t * t * ((2 + 1) * t + 2) + 1.0;
  198. }
  199. }