如何在Flutter中停用或覆盖Android"BACK"按钮?

Jac*_*pap 56 flutter

有没有办法在特定页面上停用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(),
      },
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

在pageOne上我有一个按钮可以转到pageTwo:

new FloatingActionButton(
  onPressed: () {    
    Navigator.of(context).pushNamed('/pageTwo');
  },
)
Run Code Online (Sandbox Code Playgroud)

我的问题是,如果我按下Android屏幕底部的后退箭头,我会回到pageOne.我希望这个按钮根本不显示.理想情况下,除非用户将手指按在屏幕上5秒钟,否则我希望没有可能的方法离开此屏幕.(我正在尝试为幼儿写一个应用程序,并希望只有父母能够导航出特定的屏幕).

Rém*_*let 95

答案是WillPopScope.它将阻止页面被系统弹出.你仍然可以使用Navigator.of(context).pop()

@override
Widget build(BuildContext context) {
  return new WillPopScope(
    onWillPop: () async => false,
    child: new Scaffold(
      appBar: new AppBar(
        title: new Text("data"),
        leading: new IconButton(
          icon: new Icon(Icons.ac_unit),
          onPressed: () => Navigator.of(context).pop(),
        ),
      ),
    ),
  );
}
Run Code Online (Sandbox Code Playgroud)

  • 对于那些想要拦截 Form 的弹出窗口的人来说,使用 Form 的 onWillPop 属性会更方便。它可以访问表单状态,并且可以首先检查是否存在用户可能不想丢失的状态。 (4认同)
  • 如果有人想在 pop() 之前做一些事情,可以使用这个`onWillPop: () async { onBack(); // "DO YOUR FUNCTION IS HERE WHEN POP" return false; }` (3认同)

Air*_*ark 35

虽然 Remi 的回答是正确的,但通常您不想简单地阻止后退按钮,而是希望用户确认退出。

您可以通过从确认对话框中获得答案来执行类似的操作,因为onWillPop是未来。

@override
Widget build(BuildContext context) {
  return WillPopScope(
    child: Scaffold(...),
    onWillPop: () => showDialog<bool>(
      context: context,
      builder: (c) => AlertDialog(
        title: Text('Warning'),
        content: Text('Do you really want to exit'),
        actions: [
          FlatButton(
            child: Text('Yes'),
            onPressed: () => Navigator.pop(c, true),
          ),
          FlatButton(
            child: Text('No'),
            onPressed: () => Navigator.pop(c, false),
          ),
        ],
      ),
    ),
  );
}
Run Code Online (Sandbox Code Playgroud)


Nhậ*_*rần 10

答案也许你知道那就是使用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,
        );
}
Run Code Online (Sandbox Code Playgroud)

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


小智 9

只是一个简单的方法。用 WillPopScope 小部件包裹脚手架。

  WillPopScope(
    onWillPop: () async => false,
    child: Scaffold();
Run Code Online (Sandbox Code Playgroud)


Cop*_*oad 7

您可以使用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
    },
  );
}
Run Code Online (Sandbox Code Playgroud)

  • 仅供参考,这相当于 `onWillPop: () async =&gt; _allow`。 (2认同)

Bry*_*cel 6

我在这里发布这个以防有人发现这个并希望他们能找到一个简单的例子 https://gist.github.com/b-cancel/0ca372017a25f0c120b14dfca3591aa5

import 'package:flutter/material.dart';

import 'dart:async';

void main() => runApp(new BackButtonOverrideDemoWidget());

class BackButtonOverrideDemoWidget extends StatefulWidget{
  @override
  _BackButtonOverrideDemoWidgetState createState() => new _BackButtonOverrideDemoWidgetState();
}

class _BackButtonOverrideDemoWidgetState extends State<BackButtonOverrideDemoWidget> with WidgetsBindingObserver{

  //-------------------------Test Variable

  bool isBackButtonActivated = false;

  //-------------------------Required For WidgetsBindingObserver

  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addObserver(this);
  }

  @override
  void dispose() {
    WidgetsBinding.instance.removeObserver(this);
    super.dispose();
  }

  //-------------------------Function That Triggers when you hit the back key

  @override
  didPopRoute(){
    bool override;
    if(isBackButtonActivated)
      override = false;
    else
      override = true;
    return new Future<bool>.value(override);
  }

  //-------------------------Build Method

  @override
  Widget build(BuildContext context) {
    return new Directionality(
      textDirection: TextDirection.ltr,
      child: new Container(
          color: (isBackButtonActivated) ? Colors.green : Colors.red,
          child: new Center(
              child: new FlatButton(
                color: Colors.white,
                onPressed: () {
                  isBackButtonActivated = !isBackButtonActivated;
                  setState(() {});
                },
                child: (isBackButtonActivated) ?
                new Text("DeActive the Back Button") : new Text("Activate the Back Button"),
              )
          )
      ),
    );
  }
}
Run Code Online (Sandbox Code Playgroud)


Mar*_*rcG 6

正如RémiRousselet所指出的那样,WillPopScope通常是要走的路。但是,如果要开发一个有状态的小部件,该小部件应直接对后退按钮做出反应,则可以使用以下方法:

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

  • @CopsOnRoad不,因为它不是对另一个答案的评论,而是解决同一问题的完全不同的方法。 (6认同)
  • 这是一个很好的选择,就像一个魅力,感谢您在单独的答案中强调它 (4认同)
  • 这是一个很好的选择,如果它是评论的一部分,它可能会被忽略。 (3认同)

mik*_*l98 6

所选答案已过时

\n

WillPopScope现已弃用,不应再使用。参考:Android 预测返回

\n
\n

为了支持 Android 14\xe2\x80\x99s Predictive Back 功能,一组提前 API 取代了即时导航 API,例如 WillPopScope 和 Navigator.willPop。

\n
\n
\n

替代品

\n

如果您使用的是Flutter 3.14.0-7.0.pre或更高版本,则应将WillPopScopewidgets 替换为PopScope. 它有 2 个字段:

\n
    \n
  • bool canPop, 启用/禁用系统后退手势(弹出);
  • \n
  • void Function(bool didPop)? onPopInvoked,是一个总是在系统返回手势时调用的回调,即使设置为 false,但在这种情况下canPop路线不会弹出,并且didPop将设置为 false(因此您可以检查其值以区分逻辑)。
  • \n
\n

回答

\n

回答你的问题:

\n
    \n
  • 如果您想停用“后退”按钮(即禁用系统后退手势),您可以设置canPop: false
  • \n
  • 如果您想覆盖其行为,您可以设置canPop: true(或使用某些逻辑条件或同步函数计算其值)并使用onPopInvoked: (bool didPop) {}.
  • \n
\n

例子

\n
PopScope(\n  canPop: _isSettingsChanged(),\n  onPopInvoked: (bool didPop) async {\n    if (didPop) {\n      return;\n    }\n    final NavigatorState navigator = Navigator.of(context);\n    final bool? shouldPop = await _showConfirmDialog("Unsaved settings. Discard?");\n    if (shouldPop ?? false) {\n      navigator.pop();\n    }\n  },\n  child: child,\n)\n
Run Code Online (Sandbox Code Playgroud)\n