Flutter中如何通过backButtonDispatcher禁用Android系统返回键?
问题描述
我们都知道WillPopScope可以用来拦截返回键,示例代码如下:
return WillPopScope( onWillPop: () async => false, child: Scaffold(...));
但在结合Beamer和MaterialApp.router的复杂场景中,即使使用WillPopScope,系统返回键仍会触发退出应用的操作。
因此尝试通过MaterialApp.router的backButtonDispatcher参数自定义DoNothingBackButtonDispatcher类来从更深层级禁用返回键,代码如下:
class DoNothingBackButtonDispatcher extends BackButtonDispatcher with WidgetsBindingObserver { DoNothingBackButtonDispatcher(); @override void addCallback(ValueGetter<Future<bool>> callback) {} @override void removeCallback(ValueGetter<Future<bool>> callback) {} @override Future<bool> didPopRoute() => invokeCallback(Future<bool>.value(false)); @override ChildBackButtonDispatcher createChildBackButtonDispatcher() => ChildBackButtonDispatcher(this); @override void deferTo(ChildBackButtonDispatcher child) {} @override void forget(ChildBackButtonDispatcher child) {} @override Future<bool> invokeCallback(Future<bool> defaultValue) => SynchronousFuture<bool>(false); bool onPop(BuildContext context, Route<dynamic> route) => false; @override void takePriority() {} } void main() => runApp(MyApp()); class MyApp extends StatelessWidget { MyApp({Key? key}) : super(key: key); final rootBeamerDelegate = BeamerDelegate( initialPath: Sailor.initialPath, locationBuilder: RoutesLocationBuilder( routes: { '*': (context, state, data) => const HomePage(), }, ), ); @override Widget build(BuildContext context) { return MaterialApp.router( debugShowCheckedModeBanner: false, routerDelegate: rootBeamerDelegate, routeInformationParser: BeamerParser(), backButtonDispatcher: DoNothingBackButtonDispatcher(), // <----- HERE ); } }
但点击系统返回键仍会退出应用,请问如何正确实现抽象类BackButtonDispatcher以忽略返回键点击?
解决方案
你的自定义BackButtonDispatcher失效的核心原因是**didPopRoute方法返回了false**——根据Flutter规则,返回false表示当前Dispatcher未处理返回请求,系统会继续执行默认的退出逻辑;只有返回true,才表示已处理该请求,阻止系统后续操作。
同时不需要冗余override所有方法,只需要实现核心的两个方法即可,简化后的正确实现如下:
class DoNothingBackButtonDispatcher extends BackButtonDispatcher { @override Future<bool> didPopRoute() async { // 返回true,告知系统已处理返回键请求,阻止默认退出行为 return true; } @override ChildBackButtonDispatcher createChildBackButtonDispatcher() { // 创建子Dispatcher并设置优先级,确保子路由层级也继承拦截逻辑 return ChildBackButtonDispatcher(this)..takePriority(); } }
另外需要注意:BeamerDelegate默认会创建自身的BeamerBackButtonDispatcher处理路由返回,它可能优先于你设置的全局Dispatcher生效。因此需要将自定义Dispatcher同时关联到BeamerDelegate中,修改rootBeamerDelegate的初始化代码:
final rootBeamerDelegate = BeamerDelegate( initialPath: Sailor.initialPath, locationBuilder: RoutesLocationBuilder( routes: { '*': (context, state, data) => const HomePage(), }, ), // 关联自定义的BackButtonDispatcher backButtonDispatcher: DoNothingBackButtonDispatcher(), );
这样修改后,无论全局还是Beamer路由层级,系统返回键的点击都会被完全拦截,不会触发应用退出。
内容的提问来源于stack exchange,提问作者MetaStack
相关产品推荐
相关产品推荐

