Как отключить или переопределить кнопку Android "НАЗАД" во Флаттере?

Есть ли способ отключить кнопку возврата 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(),
      },
    );
  }
}

На странице One у меня есть кнопка для перехода на страницу Two:

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

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

Ответ 1

Ответ будет 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(),
        ),
      ),
    ),
  );
}

Ответ 2

Как отметил Реми Русселе, WillPopScope - это обычно путь. Однако, если вы разрабатываете виджет с отслеживанием состояния, который должен напрямую реагировать на кнопку возврата, вы можете использовать это:

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

Ответ 3

Я размещаю это здесь, если кто-то найдет это и пожелает, чтобы они нашли простой пример 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"),
              )
          )
      ),
    );
  }
}

Ответ 4

Вы можете использовать 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
    },
  );
}

Ответ 5

Вы должны использовать метод popAndPushNamed вместо pushNamed. Он выдает текущий маршрут и нажимает желаемый маршрут.

При этом ваш код FAB должен выглядеть следующим образом:

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

Ответ 6

Я использовал миксин и виджет 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(),

Ответ 7

Хотя 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),
          ),
        ],
      ),
    ),
  );
}

Ответ 8

Вы можете использовать следующий метод:

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

Надеюсь, это поможет. Спасибо