是否有一种方法可以在特定页面上禁用Android后退按钮?

class WakeUpApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: "Time To Wake Up ?",
      home: new WakeUpHome(),
      routes: <String, WidgetBuilder>{
        '/pageOne': (BuildContext context) => new pageOne(),
        '/pageTwo': (BuildContext context) => new pageTwo(),
      },
    );
  }
}

在第一页,我有一个按钮去第二页:

new FloatingActionButton(
  onPressed: () {    
    Navigator.of(context).pushNamed('/pageTwo');
  },
)

我的问题是,如果我按下android屏幕底部的后退箭头,我就会回到pageOne。我想这个按钮不显示在所有。 理想情况下,除非用户的手指持续按在屏幕上5秒钟,否则我不希望用户有任何办法离开屏幕。(我正在尝试为幼儿编写一个应用程序,希望只有父母能够导航出特定的屏幕)。


当前回答

正如Rémi Rousselet所指出的,WillPopScope通常是可行的方法。然而,如果你正在开发一个有状态的小部件,它应该直接对后退按钮做出反应,你可以使用这个:

https://pub.dartlang.org/packages/back_button_interceptor

注意:我是这个包的作者。

其他回答

你可以使用Future.value(bool)来处理后退按钮。

bool _allow = true;

@override
Widget build(BuildContext context) {
  return WillPopScope(
    child: Scaffold(appBar: AppBar(title: Text("Back"))),
    onWillPop: () {
      return Future.value(_allow); // if true allow back else block it
    },
  );
}

答案也许你知道使用WillPopScope,但不幸的是,在IOS上你不能滑动回上一页,所以让我们自定义你的MaterialPageRoute:

class CustomMaterialPageRoute<T> extends MaterialPageRoute<T> {
  @protected
  bool get hasScopedWillPopCallback {
    return false;
  }
  CustomMaterialPageRoute({
    @required WidgetBuilder builder,
    RouteSettings settings,
    bool maintainState = true,
    bool fullscreenDialog = false,
  }) : super( 
          builder: builder,
          settings: settings,
          maintainState: maintainState,
          fullscreenDialog: fullscreenDialog,
        );
}

现在你可以使用WillPopScope并向后滑动在IOS上工作。详细答案在这里:https://github.com/flutter/flutter/issues/14203#issuecomment-540663717

如果你需要系统返回按钮点击和应用程序栏返回按钮点击有不同的行为:你可以在调用Navigator.of(context).pop()之前删除onWillPop回调:

@override
  Widget build(BuildContext context) {
    return WillPopScope(
      onWillPop: onWillPop,
      child: Scaffold(
        appBar: AppBar(
          leading: IconButton(
            onPressed: () {
              ModalRoute.of(context)?.removeScopedWillPopCallback(onWillPop);
              Navigator.of(context).pop();
            },
            icon: const Icon(Icons.arrow_back),
          ),
          title: Text(context.l10n.searchResults),
        ),
        body: MyBody(),
      ),
    );
  }

在这种情况下,当用户点击系统返回按钮时,onWillPop回调将决定是否弹出屏幕。但当用户点击应用栏后退按钮时,屏幕会立即弹出。

这里有一个替代的解决方案,如果你是用零安全编码。您需要禁用默认的后退按钮,并将其替换为IconButton。在本例中,当用户在退出前单击后退按钮确认时,我将按下AlertDialog。您可以替换此函数并将用户发送到任何其他页面

return WillPopScope(
  onWillPop: () async => false,
  child: Scaffold(
    appBar: AppBar(
      automaticallyImplyLeading: true,
      title: Text(),
      leading: IconButton(
        icon: Icon(Icons.arrow_back),
        onPressed: () => showDialog<bool>(
          context: context,
          builder: (c) => AlertDialog(
            title: Text('Warning'),
            content: Text('Are you sure you want to exit?'),
            ),
            actions: [
              TextButton(
                  child: Text('Yes'),
                  onPressed: () {
                    Navigator.pop(c, true);
                    Navigator.pop(context);
                  }),
              TextButton(
                child: Text('No'),
                onPressed: () => Navigator.pop(c, false),
              ),
            ],
          ),
        ),
      ),
    ),

对于那些想要快速退出的人:

Navigator.popAndPushNamed(context, '/your_page_route');