在Android上的Flutter应用程序中是否有任何方法拦截'Back'keydown?

时间:2017-06-19 16:18:27

标签: android dart flutter

我需要在用户通过按Android设备上的Back按钮导航离开当前路线之前显示警告对话框。我试图通过在小部件状态中实现WidgetsBindingObserver来拦截后退按钮行为。关于同一主题,GitHub上有一个关闭的issue。但是我的代码无效,因为从未调用过didPopRoute()方法。这是我的代码如下:

import 'dart:async';

import 'package:flutter/material.dart';

class NewEntry extends StatefulWidget {
  NewEntry({Key key, this.title}) :super(key: key);

  final String title;

  @override
  State<StatefulWidget> createState() => new _NewEntryState();
}

class _NewEntryState extends State<NewEntry> with WidgetsBindingObserver {
  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addObserver(this);
  }

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

  @override
  Future<bool> didPopRoute() {
    return showDialog(
      context: context,
      child: new AlertDialog(
        title: new Text('Are you sure?'),
        content: new Text('Unsaved data will be lost.'),
        actions: <Widget>[
          new FlatButton(
            onPressed: () => Navigator.of(context).pop(true),
            child: new Text('No'),
          ),
          new FlatButton(
            onPressed: () => Navigator.of(context).pop(false),
            child: new Text('Yes'),
          ),
        ],
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text(widget.title),
      ),
      floatingActionButton: new FloatingActionButton(
        child: new Icon(Icons.edit),
        onPressed: () {},
      ),
    );
  }
}

3 个答案:

答案 0 :(得分:14)

我发现解决方案是使用WillPopScope小部件。以下是最终代码:

import 'dart:async';

import 'package:flutter/material.dart';

class NewEntry extends StatefulWidget {
  NewEntry({Key key, this.title}) :super(key: key);

  final String title;

  @override
  State<StatefulWidget> createState() => new _NewEntryState();
}

class _NewEntryState extends State<NewEntry> {

  Future<bool> _onWillPop() {
    return showDialog(
      context: context,
      child: new AlertDialog(
        title: new Text('Are you sure?'),
        content: new Text('Unsaved data will be lost.'),
        actions: <Widget>[
          new FlatButton(
            onPressed: () => Navigator.of(context).pop(false),
            child: new Text('No'),
          ),
          new FlatButton(
            onPressed: () => Navigator.of(context).pop(true),
            child: new Text('Yes'),
          ),
        ],
      ),
    ) ?? false;
  }

  @override
  Widget build(BuildContext context) {
    return new WillPopScope(
      onWillPop: _onWillPop,
      child: new Scaffold(
        appBar: new AppBar(
          title: new Text(widget.title),
        ),
        floatingActionButton: new FloatingActionButton(
          child: new Icon(Icons.edit),
          onPressed: () {},
        ),
      ),
    );
  }
}

答案 1 :(得分:0)

back_button_interceptor软件包可以为您简化此过程,在更复杂的情况下尤其有用。

https://pub.dev/packages/back_button_interceptor#-readme-tab-

示例用法:

@override
void initState() {
   super.initState();
   BackButtonInterceptor.add(myInterceptor);
}

@override
void dispose() {
   BackButtonInterceptor.remove(myInterceptor);
   super.dispose();
}

bool myInterceptor(bool stopDefaultButtonEvent) {
   print("BACK BUTTON!"); // Do some stuff.
   return true;
}

答案 2 :(得分:0)

如果您使用的是GetX包,并且实现了GetMaterialApp方法来初始化您的应用程序,则永远不会调用didPopRoute中的didPushRouteWidgetsBindingObserver方法。请改用routingCallback,以下是示例,有关更多信息,请查看GetX documentation

GetMaterialApp(
  routingCallback: (routing) {
    routing.isBack ? didPopRoute() : didPushRoute(routing.current);
  }
)