因为想在 flutter
中“在调用者端获得用户是否点击 snackbar
的动作按钮”这个功能,深入研究了一下 dart
的同步方式。
本以为 Dart
中和回调函数进行同步需要用到的会是semphore
或mutex
等第三方包,而实际上只需要 dart:async
库中的 Completer
类。
同步
import 'dart:async'; import 'package:flutter/material.dart';
Future<bool> showSnackbarAndReturnResult(BuildContext context, String message) async { final completer = Completer<bool>(); final scaffoldMessenger = ScaffoldMessenger.of(context);
scaffoldMessenger.showSnackBar( SnackBar( content: Text(message), action: SnackBarAction( label: 'OK', onPressed: () { completer.complete(true); scaffoldMessenger.hideCurrentSnackBar(); }, ), ), );
return await completer.future; }
void main() { runApp(MaterialApp( home: Scaffold( appBar: AppBar( title: Text('Snackbar Example'), ), body: Center( child: ElevatedButton( onPressed: () async { final result = await showSnackbarAndReturnResult( context, 'This is a Snackbar!', ); if (result) { print('Snackbar action completed!'); } }, child: Text('Show Snackbar'), ), ), ), )); }
|
completer.future
只在 complete
或 completeError
被调用后才会完成,从而达到了同步的目的。
snackbar
同步就是这么简单,但是上述代码并不能使用在产品中,因为很不完善。比如用户不点 snackbar
的按钮,哪怕 snackbar
隐藏,completer
和函数 还是没有返回。为了完善上述功能,不能简单的使用 return await completer.future;
,而需要加上延时和 snackbar
关闭判断。
为了获得 snackbar
是否隐藏,需要使用 showSnackBar
的返回值,一个ScaffoldFeatureController
类型的 controller
。延时比较简单,使用 Future.delayed
即可。代码如下:
final completer = Completer<bool>(); ... final controller = scaffoldMessenger.showSnackBar(...); ... await Future.any([ completer.future, Future.delayed(Duration(seconds: seconds)), controller.closed, ]);
if (completer.isCompleted) { return true; } else { completer.complete(false); return false; }
|
修改 showSnackbarAndReturnResult
函数的参数,传入 seconds
即可。