FlutterでAndroidの「戻る」ボタンを無効または無効にするにはどうすればよいですか?


102

特定のページで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(),
      },
    );
  }
}

pageOneには、pageTwoに移動するためのボタンがあります。

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

私の問題は、Android画面の下部にある戻る矢印を押すと、pageOneに戻ることです。このボタンをまったく表示しないようにします。理想的には、たとえばユーザーが画面上で指を5秒間押し続けない限り、この画面から抜け出す方法はありません。(私は幼児向けのアプリを書こうとしているので、親だけが特定の画面からナビゲートできるようにしたいと思っています)。

回答:


188

答えは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からナビゲートしたいので、どうすれば管理できますか?それ。案内してくれませんか
Ravindra Kushwaha

この答えは古いかもしれません。しかし、GEMです!説明を広げることを考えてください。それは素晴らしい働きをします。ありがとうございました。
Val

1
pop()の前に何かしたい人は、これを使用できますonWillPop: () async { onBack(); // "DO YOUR FUNCTION IS HERE WHEN POP" return false; }
Huy Tower

21

RémiRousseletが指摘したように、WillPopScope通常はに行く方法です。ただし、戻るボタンに直接反応するステートフルウィジェットを開発している場合は、次のように使用できます。

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


敬意を込めて、これはコメントとしてより適していると思いませんか?
CopsOnRoad

21
@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()を参照してください。登録順にオブザーバに通知し、trueを受け取るとすぐに停止します。プッシュされたルートがある場合、ナビゲーターは最初にtrueを返し、その後、オブザーバーが実際に呼び出されることはありません。つまり、コードは、ユーザーが[戻る]ボタンをクリックしたときにルートがなくなったときにアプリケーションがシャットダウンしないようにするためにのみ機能します。
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
    },
  );
}

参考までに、これはと同等onWillPop: () async => _allowです。
Lynn

@リンはい、私はそれを知っています。Future.value()通話を共有したかっただけです。
CopsOnRoad

3

私はmixinを使用し、WillPopScopeウィジェットは私のために仕事を成し遂げることができませんでした。これは私が見つけた最善のアプローチであり、私の意見ではWillPopScopeよりもはるかに優れています。
final bool canPop = ModalRoute.of(context)?.canPop ?? false;
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(),

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の先頭にコンテナーを追加するだけです。

AppBar(
        title: new Text('Page Title'),
        leading: new Container(),
      ),
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.