Wie kann ich die Android-Schaltfläche "ZURÜCK" in Flutter deaktivieren oder überschreiben?

97

Gibt es eine Möglichkeit, die Android-Zurück-Schaltfläche auf einer bestimmten Seite zu deaktivieren?

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

Auf pageOne habe ich eine Schaltfläche, um zu pageTwo zu gelangen:

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

Mein Problem ist, dass ich, wenn ich den Zurück-Pfeil am unteren Rand des Android-Bildschirms drücke, zu pageOne zurückkehre. Ich möchte, dass dieser Button überhaupt nicht angezeigt wird. Im Idealfall möchte ich keinen Ausweg aus diesem Bildschirm haben, es sei denn, der Benutzer hält beispielsweise seinen Finger 5 Sekunden lang auf dem Bildschirm gedrückt. (Ich versuche, eine App für Kleinkinder zu schreiben, und möchte, dass nur die Eltern aus dem jeweiligen Bildschirm heraus navigieren können.)

Jackpap
quelle

Antworten:

177

Die Antwort lautet WillPopScope. Dadurch wird verhindert, dass die Seite vom System geöffnet wird. Sie können weiterhin verwendenNavigator.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(),
        ),
      ),
    ),
  );
}
Rémi Rousselet
quelle
1
Für diejenigen, die den Pop eines Formulars abfangen möchten, ist es bequemer, die onWillPopEigenschaft des Formulars zu verwenden . Es hat Zugriff auf den Formularstatus und kann zunächst überprüfen, ob ein Status vorhanden ist, den der Benutzer möglicherweise nicht verlieren möchte.
Joe Lapp
Hallo @ RémiRousselet, können Sie mir bitte beim Verwalten des Backstacks helfen, als hätte ich einen Stapel von A-, B-, C-, D-Bildschirmen und möchte von D-> B ODER D-> A navigieren. Wie werde ich dann verwalten? es. Können Sie mich bitte darauf
hinweisen
Ich kenne diese Antwort vielleicht alt. Aber ist ein Juwel! Denken Sie darüber nach, die Erklärung zu erweitern. Es funktioniert hervorragend. Danke dir.
Val
1
Für jemanden, der etwas vor pop () tun möchte, kann dies verwendet werdenonWillPop: () async { onBack(); // "DO YOUR FUNCTION IS HERE WHEN POP" return false; }
Huy Tower
20

Wie Rémi Rousselet betonte, WillPopScopeist dies normalerweise der richtige Weg. Wenn Sie jedoch ein Stateful-Widget entwickeln, das direkt auf die Schaltfläche "Zurück" reagieren soll, können Sie Folgendes verwenden:

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

MarcG
quelle
Glauben Sie nicht, dass dies mit vollem Respekt besser als Kommentar geeignet ist?
CopsOnRoad
19
@CopsOnRoad Nein, da es sich nicht um einen Kommentar zu einer anderen Antwort handelt, sondern um einen völlig anderen Weg, um dasselbe Problem zu lösen.
MarcG
13

Während Remis Antwort richtig ist, möchten Sie normalerweise nicht einfach die Zurück-Taste blockieren, sondern möchten, dass ein Benutzer den Ausgang bestätigt.

Sie können dies auf ähnliche Weise tun, indem Sie im Bestätigungsdialog eine Antwort erhalten, da dies onWillPopeine Zukunft ist.

@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),
          ),
        ],
      ),
    ),
  );
}
Airon Tark
quelle
Warum wird diese Antwort abgelehnt? Implementiert jemand dies und hat schlechte Erfahrungen gemacht?
SamiAzar
Ich möchte zum vorherigen Bildschirm wechseln, anstatt zum ersten Bildschirm zu wechseln, nachdem ich die Zurück-Taste vom Gerät aus gedrückt habe. Ich brauche kein solches Dialogfeld. Was soll ich tun
LakshmiYogeshwaran
3

Ich poste dies hier, falls jemand da draußen dies findet und wünscht, er würde ein einfaches Beispiel finden 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"),
              )
          )
      ),
    );
  }
}
Bryan Abbrechen
quelle
Ich habe es gestern buchstäblich selbst benutzt. Denken Sie daran, dass es nur für Android ist, Apple hat keine Zurück-Taste. Könnten Sie mir vielleicht sagen, was schief geht, damit ich es reparieren kann, oder vielleicht funktioniert es nur auf meinem speziellen Emulator. Ich habe mein Flattern seit ein paar Wochen nicht mehr aktualisiert. Vielleicht ist das das Problem. Lassen Sie mich wissen
Bryan Abbrechen
@BryanCancel Ihre Antwort funktioniert nur, wenn Sie noch keine Push-Routen haben. Siehe Methode WidgetsBinding.handlePopRoute (). Es benachrichtigt die Beobachter in der Registrierungsreihenfolge und stoppt, sobald es wahr erhält. Wenn Push-Routen vorhanden sind, gibt der Navigator zuerst true zurück, und dann wird Ihr Beobachter nie angerufen. Mit anderen Worten, Ihr Code verhindert nur, dass die Anwendung heruntergefahren wird, wenn der Benutzer auf die Schaltfläche "Zurück" klickt und keine weiteren Routen mehr vorhanden sind.
MarcG
2

Sie können Future.value(bool)den Zurück-Button verwenden.

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
    },
  );
}
CopsOnRoad
quelle
Zu Ihrer Information, dies entspricht onWillPop: () async => _allow.
Lynn
@Lynn ja das weiß ich. Ich wollte nur den Future.value()Anruf teilen .
CopsOnRoad
1

Ich habe Mixin verwendet und das WillPopScope-Widget konnte den Job einfach nicht für mich erledigen. Dies ist der beste Ansatz, den ich gefunden habe, meiner Meinung nach viel besser als WillPopScope.
final bool canPop = ModalRoute.of(context)?.canPop ?? false;
Verwendet es so in der Appbar:

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(),
Djordje Komazec
quelle
1

Die Antwort, vielleicht wussten Sie, dass WillPopScope verwendet wird , aber unter IOS können Sie leider nicht zur vorherigen Seite wischen. Passen Sie also Ihre MaterialPageRoute an:

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

Jetzt können Sie WillPopScope verwenden und nach hinten wischen funktioniert unter IOS. Die Detailantwort finden Sie hier: https://github.com/flutter/flutter/issues/14203#issuecomment-540663717

Nhật Trần
quelle
0

Fügen Sie einfach einen Container oben in der Appbar hinzu, der die Schaltfläche "Zurück" verbirgt.

AppBar(
        title: new Text('Page Title'),
        leading: new Container(),
      ),
Niroop Nife
quelle
-5

Sie können folgende Methode verwenden:

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

Hoffe das hilft. Vielen Dank

Bernard Nongpoh
quelle