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

时间:2017-08-28 10:13:40

标签: 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(),
      },
    );
  }
}

在页面上我有一个按钮转到pageTwo:

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

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

12 个答案:

答案 0 :(得分:55)

答案是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(),
        ),
      ),
    ),
  );
}

答案 1 :(得分:3)

尽管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),
          ),
        ],
      ),
    ),
  );
}

答案 2 :(得分:2)

我在这里张贴这个,以防有人在那里找到这个并希望他们能找到一个简单的例子 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"),
              )
          )
      ),
    );
  }
}

答案 3 :(得分:2)

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

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

答案 4 :(得分:2)

答案也许您知道使用 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

答案 5 :(得分:1)

您可以使用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
    },
  );
}

答案 6 :(得分:1)

只需在应用栏的顶部添加一个容器即可隐藏后退按钮。

AppBar(
        title: new Text('Page Title'),
        leading: new Container(),
      ),

答案 7 :(得分:1)

如果您使用空安全编码,这里有一个替代解决方案。您需要禁用默认的后退按钮,并将其替换为 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),
              ),
            ],
          ),
        ),
      ),
    ),

答案 8 :(得分:0)

您应该使用方法popAndPushNamed而不是pushNamed。它弹出当前路线并推动所需路线。

话虽如此,您的FAB代码应如下所示

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

答案 9 :(得分:0)

我使用mixin和WillPopScope小部件只是无法为我完成工作。 我发现这是最好的方法,比我认为的WillPopScope好得多。
final bool canPop = ModalRoute.of(context)?.canPop ?? false;
在应用栏内这样使用它:

leading: ModalRoute.of(context)?.canPop ?? false
    ? IconButton(
        onPressed: () {
          Navigator.pop(context);
        },
        icon: (Platform.isAndroid)
            ? const Icon(Icons.arrow_back)
            : const Icon(Icons.arrow_back_ios),
      )
    : Container(),

答案 10 :(得分:0)

尝试这个会杀死你的应用状态

@override
  Widget build(BuildContext context) {
    return WillPopScope(
      ////////////////
      onWillPop: () => showDialog<bool>(
        context: context,
        builder: (c) => AlertDialog(
          title: Text(
            'Warning',
            textAlign: TextAlign.center,
          ),
          content: Text('Are you sure to exit?'),
          actions: [
            TextButton(
              style: TextButton.styleFrom(
                primary: Colors.green,
              ),
              onPressed: () async {
                exit(0);// kill app
              },
              child: Text('Yes'),
            ),
            TextButton(
              style: TextButton.styleFrom(
                primary: Colors.red,
              ),
              onPressed: () => Navigator.pop(c, false),
              child: Text('No'),
            )
          ],
        ),
      ),
      /////////////////////
      child: Scaffold(),
    );
  }

答案 11 :(得分:-2)

您可以使用的方法如下:

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

希望这会有所帮助。谢谢