Як деактивувати або замінити кнопку Android "НАЗАД" у Flutter?


110

Чи є спосіб деактивувати кнопку "Назад" на 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(),
      },
    );
  }
}

На сторінціОдна у мене є кнопка для переходу на сторінкуДва:

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

Моя проблема полягає в тому, що якщо я натискаю стрілку Назад внизу екрану Android, я повертаюся до pageOne. Я хотів би, щоб ця кнопка взагалі не відображалася. В ідеалі, я не хотів би мати жодного можливого виходу з цього екрану, якщо користувач, наприклад, не утримує палець на екрані протягом 5 секунд. (Я намагаюся написати програму для малюків, і хотів би, щоб лише батьки мали можливість вийти з певного екрану).

Відповіді:


198

Відповідь така 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
Тим, хто хоче перехопити спливаючу форму, зручніше використовувати onWillPopвластивість форми . Він має доступ до стану форми і може спочатку перевірити, чи є якийсь стан, який користувач може не хотіти втратити.
Джо Лапп,

Привіт @ RémiRousselet, чи не можете ви допомогти мені керувати зворотним стеком, як у мене є стек екранів A, B, C, D, і я хочу перейти з D-> B АБО D-> A, тоді як я буду керувати це. Чи можете ви, будь ласка, направити мене на це
Равіндра Кушваха,

Я знаю цю відповідь, можливо, давню. Але це GEM! Подумайте над розширенням пояснення. Це працює чудово. Дякую.
Валь

1
Якщо хтось хоче щось зробити до pop (), може скористатися цимonWillPop: () async { onBack(); // "DO YOUR FUNCTION IS HERE WHEN POP" return false; }
Huy Tower

24

Як зазначав Ремі Русселет, WillPopScopeзазвичай це шлях. Однак, якщо ви розробляєте віджет, що реагує на кнопку "Назад", ви можете використовувати це:

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

Примітка. Я автор цього пакету.


З повагою, чи не вважаєте ви, що це більше підходить як коментар?
CopsOnRoad

25
@CopsOnRoad Ні, оскільки це не коментар до іншої відповіді, а зовсім інший спосіб вирішення тієї самої проблеми.
MarcG

Це хороша альтернатива, і її можна було б проігнорувати, якби це було частиною коментаря.
abhijat_saxena

16

Хоча відповідь Ремі є правильною, як правило, ви не хочете просто заблокувати кнопку "Назад", а хочете, щоб користувач підтвердив вихід.

Ви можете зробити це подібним чином, отримавши відповідь із діалогового вікна підтвердження, оскільки 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),
          ),
        ],
      ),
    ),
  );
}

Чому ця відповідь отримує проти? Хтось це впроваджував і мав поганий досвід?
SamiAzar

Я хочу перейти на попередній екран, а не перейти на перший екран після натискання кнопки назад на пристрої. Мені не потрібне таке діалогове вікно. Що мені робити
Лакшмі Йогешваран

4

Я публікую це тут, якщо хтось там знайде це і побажає, що він знайде простий приклад 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"),
              )
          )
      ),
    );
  }
}

Вчора я буквально сам цим користувався. Майте на увазі, що це лише для Android, у Apple немає кнопки повернення. Хоча не могли б ви сказати мені, що йде не так, щоб я міг це відновити, або, можливо, це працює лише на моєму конкретному емуляторі. Я не оновлював тріпотіння вже пару тижнів, тож, можливо, це проблема. Повідомте мене
Брайан Скасувати

@BryanCancel Ваша відповідь працює лише в тому випадку, якщо у вас ще немає жодного проштовхуваного маршруту. Див. Метод WidgetsBinding.handlePopRoute (). Він повідомляє спостерігачів у порядку реєстрації та зупиняється, як тільки отримує істину. Коли є маршрутні маршрути, навігатор спочатку повертає істину, а потім ваш спостерігач насправді ніколи не викликається. Іншими словами, ваш код працює лише для того, щоб запобігти вимкненню програми, коли користувач натискає кнопку "Назад", коли не залишилося більше маршрутів.
MarcG

3

Ви можете скористатися 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
    },
  );
}

FYI, це еквівалентно onWillPop: () async => _allow.
Лінн,

@Lynn так, я це знаю. Я просто хотів поділитися Future.value()дзвінком.
CopsOnRoad

3

Я використовував 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(),

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


1

Просто додайте контейнер на початку панелі програм, який приховує кнопку "Назад".

AppBar(
        title: new Text('Page Title'),
        leading: new Container(),
      ),
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.