fluttertoast
目前Flutter官方暂未提供toast工具类,可以利用第三方库fluttertoast
Github:https://github.com/PonnamKarthik/FlutterToast
DartHub: https://pub.dartlang.org/packages/fluttertoast
1 2 3 4 5 6 7 8 9 10 11
| import 'package:fluttertoast/fluttertoast.dart';
Fluttertoast.showToast( msg: "This is Center Short Toast", toastLength: Toast.LENGTH_SHORT, gravity: ToastGravity.CENTER, timeInSecForIos: 1, backgroundColor: Colors.red, textColor: Colors.white, fontSize: 16.0 );
|
Overlay实现
Draggable源码中有这么一段:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| class _DragAvatar<T> extends Drag { _DragAvatar({ @required this.overlayState, this.data, this.axis, Offset initialPosition, this.dragStartPoint = Offset.zero, this.feedback, this.feedbackOffset = Offset.zero, this.onDragEnd, @required this.ignoringFeedbackSemantics, }) : assert(overlayState != null), assert(ignoringFeedbackSemantics != null), assert(dragStartPoint != null), assert(feedbackOffset != null) { _entry = OverlayEntry(builder: _build); overlayState.insert(_entry); _position = initialPosition; updateDrag(initialPosition); } }
|
_DragAvatar是Draggable中的私有类,主要作用是当识别到拖拽事件的时候,在屏幕上绘制相应的Widget跟随手指移动。可以看到,绘制跟随手指移动的Widget的关键代码是创建一个OverlayEntry,然后将其添加到OverlayState中。
OverlayState事实上是有一个Overlay的Widget,是一个StatefullWidget,它的createState方法获取的就是OverlayState对象。
Overlay可以认为是一个UI上面的蒙版/浮空层,使用起来类似Stack,如何使用:通过Overlay.of获得OverlayState对象,调用OverlayState.insert添加OverlayEntry,当不需要的时候,通过OverlayEntry.remove移除OverlayEntry。
OverlayState使用示例:
1 2 3 4 5 6 7 8 9
| OverlayState overlayState = Overlay.of(context);
OverlayEntry _overlayEntry = OverlayEntry( builder: (BuildContext context) => Positioned( child: Icon(Icons.android), ));
overlayState.insert(_overlayEntry);
|
这样就可以在屏幕上显示一个Icon。并且可以通过修改Positioned的left,top,right,bottom等值来修改Overlay在屏幕中的位置。最后,通过_overlayEntry.remove();进行移除,让Overlay在屏幕上消失。
例如我们做一个出现2秒后消失的Icon:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| void addOverlayAutoHide() async { OverlayState overlayState = Overlay.of(context); OverlayEntry _overlayEntry = OverlayEntry( builder: (BuildContext context) => Positioned( child: Icon(Icons.android), )); overlayState.insert(_overlayEntry); await Future.delayed(Duration(seconds: 2)); _overlayEntry.remove(); }
|
做到这里,思路已经很清晰了。稍微修改一下OverlayEntry的build方法返回一个符合要求的toast,然后加个渐变透明的动画。基本上就能满足我们的需求啦。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
| class MyToast { static OverlayEntry _overlayEntry; static bool _showing = false; static DateTime _startedTime; static String _msg;
static void toast( BuildContext context, String msg, ) async { assert(msg != null); _msg = msg; _startedTime = DateTime.now();
OverlayState overlayState = Overlay.of(context); _showing = true; if (_overlayEntry == null) { _overlayEntry = OverlayEntry( builder: (BuildContext context) => Positioned( top: MediaQuery.of(context).size.height * 2 / 3, child: Container( alignment: Alignment.center, width: MediaQuery.of(context).size.width, child: Padding( padding: EdgeInsets.symmetric(horizontal: 80.0), child: AnimatedOpacity( opacity: _showing ? 1.0 : 0.0, duration: _showing ? Duration(milliseconds: 100) : Duration(milliseconds: 400), child: _buildToastWidget(), ), )), )); overlayState.insert(_overlayEntry); } else { _overlayEntry.markNeedsBuild(); } await Future.delayed(Duration(milliseconds: 2000));
if (DateTime.now().difference(_startedTime).inMilliseconds >= 2000) { _showing = false; _overlayEntry.markNeedsBuild(); } }
static _buildToastWidget() { return Center( child: Card( color: Colors.black26, child: Padding( padding: EdgeInsets.symmetric(horizontal: 10.0, vertical: 5.0), child: Text( _msg, style: TextStyle( fontSize: 14.0, color: Colors.white, ), ), ), ), ); } }
|
