Jak dezaktywować lub zastąpić przycisk „WSTECZ” Androida w aplikacji Flutter?


112

Czy istnieje sposób na dezaktywację przycisku Wstecz Androida na określonej stronie?

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

Na pageOne Mam przycisk, aby przejść do strony Dwa:

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

Mój problem polega na tym, że jeśli naciśnę strzałkę Wstecz u dołu ekranu Androida, wracam do strony pierwszej. Chciałbym, żeby ten przycisk w ogóle się nie pojawiał. Najlepiej, gdybym nie miał możliwości wyjścia z tego ekranu, chyba że użytkownik przykładowo przytrzyma palec na ekranie przez 5 sekund. (Próbuję napisać aplikację dla małych dzieci i chciałbym, aby tylko rodzice mogli opuścić dany ekran).

Odpowiedzi:


202

Odpowiedź jest WillPopScope. Zapobiegnie to wyświetlaniu strony przez system. Nadal będziesz mógł korzystać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
Dla tych, którzy chcą przechwycić pop formularza, wygodniej jest użyć właściwości Form onWillPop. Ma dostęp do stanu formularza i może najpierw sprawdzić, czy istnieje stan, którego użytkownik nie chciałby utracić.
Joe Lapp

Cześć @ RémiRousselet, Czy możesz mi pomóc w zarządzaniu stosem z tyłu, tak jakbym miał stos ekranów A, B, C, D i chcę nawigować z D-> B LUB D-> A, to jak sobie poradzę to. Czy możesz mnie w tym
poprowadzić

Wiem, że ta odpowiedź może być stara. Ale to klejnot! Pomyśl o rozszerzeniu wyjaśnienia. Działa znakomicie. Dziękuję Ci.
Val

1
Dla kogoś, kto chce coś zrobić przed pop (), może użyć tegoonWillPop: () async { onBack(); // "DO YOUR FUNCTION IS HERE WHEN POP" return false; }
Huy Tower

24

Jak zauważył Rémi Rousselet, WillPopScope zazwyczaj jest to najlepszy sposób. Jeśli jednak tworzysz widżet stanowy, który powinien reagować bezpośrednio na przycisk Wstecz, możesz użyć tego:

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

Uwaga: jestem autorem tego pakietu.


Z całym szacunkiem, czy nie sądzisz, że lepiej pasuje to jako komentarz?
CopsOnRoad

25
@CopsOnRoad Nie, ponieważ nie jest to komentarz do innej odpowiedzi, a raczej zupełnie inny sposób rozwiązania tego samego problemu.
MarcG

To dobra alternatywa i mogłaby zostać zignorowana, gdyby była częścią komentarza.
abhijat_saxena

17

Chociaż odpowiedź Remiego jest prawidłowa, zwykle nie chcesz po prostu blokować przycisku Wstecz, ale chcesz, aby użytkownik potwierdził wyjście.

Możesz to zrobić w podobny sposób, uzyskując odpowiedź z okna dialogowego potwierdzenia, ponieważ onWillPopto przyszłość.

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

Dlaczego ta odpowiedź jest przeciwna? Czy ktoś to wdraża i miał złe doświadczenia?
SamiAzar

Chcę przejść do poprzedniego ekranu, a raczej przejść do pierwszego ekranu po naciśnięciu przycisku Wstecz na urządzeniu. Nie potrzebuję takiego okna dialogowego. Co powinienem zrobić
LakshmiYogeshwaran

4

Publikuję to tutaj, na wypadek, gdyby ktoś to znalazł i chciałby znaleźć prosty przykład 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"),
              )
          )
      ),
    );
  }
}

Sam go wczoraj dosłownie użyłem. Pamiętaj, że jest to tylko dla Androida, Apple nie ma przycisku Wstecz. Chociaż możesz mi powiedzieć, co poszło nie tak, abym mógł to naprawić, a może działa tylko na moim konkretnym emulatorze. Nie aktualizowałem trzepotania od kilku tygodni, więc może to jest problem. Daj mi znać
Bryan Anuluj

@BryanCancel Twoja odpowiedź działa tylko wtedy, gdy nie masz jeszcze żadnych wymuszonych tras. Zobacz metodę WidgetsBinding.handlePopRoute (). Powiadamia obserwatorów w kolejności rejestracji i zatrzymuje się, gdy tylko otrzyma prawdę. W przypadku tras wypychanych nawigator najpierw zwraca wartość true, a następnie obserwator nigdy nie zostaje wywołany. Innymi słowy, twój kod działa tylko po to, aby zapobiec wyłączaniu aplikacji, gdy użytkownik kliknie przycisk Wstecz, gdy nie ma już żadnych tras.
MarcG,

3

Możesz użyć Future.value(bool)do obsługi przycisku Wstecz.

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

FYI, to jest równoważne z onWillPop: () async => _allow.
Lynn

@Lynn tak, wiem to. Chciałem tylko podzielić się Future.value()rozmową.
CopsOnRoad,

3

Użyłem mixin i widżetu WillPopScope po prostu nie mogłem wykonać tej pracy za mnie. To najlepsze podejście, które znalazłem, znacznie lepsze niż WillPopScope.
final bool canPop = ModalRoute.of(context)?.canPop ?? false;
Użyłem tego w następujący sposób na pasku aplikacji:

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

2

Odpowiedź może wiedziałeś, że to użycie WillPopScope , ale niestety na IOS nie możesz przesunąć palcem do poprzedniej strony, więc dostosujmy twoją 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,
        );
}

Teraz możesz użyć WillPopScope i przesunąć palcem do tyłu będzie działać na IOS. Odpowiedź na szczegóły jest tutaj: https://github.com/flutter/flutter/issues/14203#issuecomment-540663717


1

Po prostu dodaj kontener na początku paska aplikacji, który ukrywa przycisk Wstecz.

AppBar(
        title: new Text('Page Title'),
        leading: new Container(),
      ),
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.