import 'dart:async'; import 'dart:ui'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:link/view/component/loading.dart'; import '../../utils/size_fit.dart'; class Toast { static final Toast _instance = Toast._internal(); factory Toast() => _instance; OverlayEntry? _overlayEntry; bool _showing = false; Timer? _timer; AnimationController? controller; Toast._internal(); // txt void showText(String text, {required BuildContext context}) { // ignore: non_constant_identifier_names Widget RCCardText = Card( color: Colors.black87, child: Padding( padding: const EdgeInsets.all(10), child: Text( text, style: const TextStyle(fontSize: 15, color: Colors.white), ), ), ); _autoRemove(RCCardText, text, context: context); } // success void showSuccessText(String text, {required BuildContext context}) { _showIconInfoText(text, "assets/images/toast_success.png", context); } // info void showInfoText(String text, {required BuildContext context}) { _showIconInfoText(text, "assets/images/toast_tip.png", context); } // error void showErrorText(String text, {required BuildContext context}) { _showIconInfoText(text, "assets/images/alter_wro.png", context); } // hud + text void showHudText(String text, {required BuildContext context}) { // ignore: non_constant_identifier_names Widget HudText = Container( height: 80, decoration: const BoxDecoration( color: Colors.black54, borderRadius: BorderRadius.all(Radius.circular(24)), ), padding: const EdgeInsets.fromLTRB(32, 24, 32, 24), child: Column( children: [ Container( width: 60, height: 40, padding: const EdgeInsets.all(10), child: Theme( data: ThemeData( cupertinoOverrideTheme: const CupertinoThemeData( brightness: Brightness.dark, ), ), child: const CupertinoActivityIndicator( radius: 16, ), ), ), Material( color: Colors.transparent, child: Text( text, style: const TextStyle( fontSize: 16, color: Colors.white, ), ), ), ], ), ); _handMovementRemove(HudText, context: context); } // hud void showHud({required BuildContext context}) { // ignore: non_constant_identifier_names Widget Hud = ClipRRect( borderRadius: BorderRadius.all(Radius.circular(24.px)), child: BackdropFilter( filter: ImageFilter.blur(sigmaX: 10.0, sigmaY: 10.0), child: Container( width: 112.px, height: 112.px, color: const Color(0xB34D4D4D), alignment: Alignment.center, child: const Loading(), ), ), ); _handMovementRemove(Hud, context: context); } //alert void showCustomHud(Widget child, {required BuildContext context}) { // ignore: non_constant_identifier_names Widget Hud = Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ ClipRRect( borderRadius: BorderRadius.all(Radius.circular(24.px)), child: BackdropFilter( filter: ImageFilter.blur(sigmaX: 10.0, sigmaY: 10.0), child: Container( width: 288.px, // height: 112.px, color: const Color(0xB34D4D4D), alignment: Alignment.center, child: Material( color: Colors.transparent, child: child, ), ), ), ) ], ); _handMovementRemove(Hud, context: context); } // dismiss void hideHud() { if (_overlayEntry != null) { _overlayEntry?.remove(); _timer?.cancel(); _overlayEntry = null; } } void _showIconInfoText(String text, String imageName, BuildContext context) { // ignore: non_constant_identifier_names Widget RCIconText = Column(children: [ SizedBox( height: 100.px, ), ClipRRect( borderRadius: BorderRadius.all(Radius.circular(24.px)), child: BackdropFilter( filter: ImageFilter.blur(sigmaX: 10.0, sigmaY: 10.0), child: Container( color: const Color(0xB34D4D4D), padding: EdgeInsets.fromLTRB(32.px, 24.px, 32.px, 24.px), child: Column( children: [ Image.asset( imageName, width: 48.px, height: 48.px, ), SizedBox( height: 12.px, ), Material( color: Colors.transparent, child: Text( text, textAlign: TextAlign.center, style: TextStyle(color: Colors.white, fontSize: 16.px), ), ), ], ), ), )) ]); _autoRemove(RCIconText, text, context: context); } void _autoRemove(Widget child, String text, {required BuildContext context}) { hideHud(); // 简单写个消失的动画,可自行自定义 _showing = true; _setOverlayEntry( AnimatedOpacity( opacity: _showing ? 1.0 : 0.0, duration: _showing ? const Duration(milliseconds: 50) : const Duration(milliseconds: 100), child: child, ), context); _removeText(text); } void _handMovementRemove(Widget child, {required BuildContext context}) { hideHud(); _setOverlayEntry(child, context); } void _setOverlayEntry(Widget child, BuildContext context) { if (context == null) { // context = RCGlobalKey.currentState.context; } if (context == null) throw ("Error: Context is null, Please call init(context) before showing toast."); if (_overlayEntry == null) { _overlayEntry = OverlayEntry( builder: (BuildContext context) => Positioned( top: MediaQuery.of(context).padding.top + kToolbarHeight, child: Container( alignment: Alignment.center, color: Colors.transparent, width: MediaQuery.of(context).size.width, height: MediaQuery.of(context).size.height - kToolbarHeight - MediaQuery.of(context).padding.top, padding: EdgeInsets.only( bottom: kToolbarHeight + MediaQuery.of(context).padding.top), child: child, ), )); //插入到整个布局的最上层 Overlay.of(context)?.insert(_overlayEntry!); } else { //重新绘制UI,类似setState _overlayEntry?.markNeedsBuild(); } } // 传入text,根据字数判断显示的时长(1-3s) void _removeText(String text) { if (_overlayEntry != null) { // 显示时间 int _showTime = text.length * 200; if (_showTime < 1000) { _showTime = 2000; } else if (_showTime > 2000) { _showTime = 2000; } _timer = Timer(Duration(milliseconds: _showTime), () { _showing = false; _overlayEntry?.markNeedsBuild(); Future.delayed(const Duration(milliseconds: 200), () { _overlayEntry?.remove(); _overlayEntry = null; _timer?.cancel(); }); }); } } }