在Flutter中将嵌套导航器与WillPopScope一起使用 [英] Use nested Navigator with WillPopScope in Flutter

查看:284
本文介绍了在Flutter中将嵌套导航器与WillPopScope一起使用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我的应用程序中,我想要一个自定义的导航(仅更改屏幕的一部分并保留我在其中所做的操作的历史记录). 为此,我使用的是导航器,它可以很好地进行简单导航. 但是,我想处理Android的后退按钮. Flutter中存在一个问题,显然这迫使我处理导航器的父小部件中的后退按钮: https://github.com/flutter/flutter/issues/14083

In my application, I want to have a custom Navigation (only change part of the screen and keep an history of what I'm doing inside it). For that purpose, I am using a Navigator and it's working fine for simple navigation. However, I want to handle the back button of Android. There is a problem with it in Flutter apparently which forces me to handle the backbutton in the parent widget of the Navigator : https://github.com/flutter/flutter/issues/14083

由于这个原因,我需要在子级中检索Navigator的实例,然后在其上调用pop().我正在尝试为此使用GlobalKey.

Due to that, I need to retrieve the instance of my Navigator in the children and call pop() on it. I am trying to use a GlobalKey for this.

我现在尝试使其工作一段时间,并制作了一个示例项目来进行测试. 这是我的代码:

I am trying to make it work for a while now and made a sample project just to test this. Here is my code :

import 'package:flutter/material.dart';

void main() {
  runApp(MaterialApp(title: 'Navigation Basics', home: MainWidget()));
}

class MainWidget extends StatelessWidget {
  final GlobalKey<NavigatorState> navigatorKey = GlobalKey();

  @override
  Widget build(BuildContext context) {
    return SafeArea(
        child: WillPopScope(
            onWillPop: () => navigatorKey.currentState.maybePop(),
            child: Scaffold(
                body: Padding(
              child: Column(
                children: <Widget>[
                  Text("Toto"),
                  Row(
                    mainAxisAlignment: MainAxisAlignment.spaceBetween,
                    children: <Widget>[
                      Expanded(
                          child: RaisedButton(
                        child: Text('First'),
                        onPressed: () {
                          navigatorKey.currentState.pushNamed('/first');
                          // Navigator.push(
                          //   context,
                          //   MaterialPageRoute(builder: (context) => SecondRoute()),
                          // );
                        },
                      )),
                      Expanded(
                          child: RaisedButton(
                        child: Text('Second'),
                        onPressed: () {
                          navigatorKey.currentState.pushNamed('/second');
                        },
                      ))
                    ],
                  ),
                  Expanded(
                      child: Stack(
                    children: <Widget>[
                      Container(
                        decoration: BoxDecoration(color: Colors.red),
                      ),
                      ConstrainedBox(
                          constraints: BoxConstraints.expand(),
                          child: _getNavigator()),
                    ],
                  )),
                ],
              ),
              padding: EdgeInsets.only(bottom: 50),
            ))));
  }

  Navigator _getNavigator() {
    return Navigator(
        key: navigatorKey,
        initialRoute: '/',
        onGenerateRoute: (RouteSettings settings) {
          WidgetBuilder builder;
          switch (settings.name) {
            case '/':
              builder = (BuildContext _) => FirstRoute();
              break;
            case '/second':
              builder = (BuildContext _) => SecondRoute();
              break;
            default:
              throw new Exception('Invalid route: ${settings.name}');
          }
          return new MaterialPageRoute(builder: builder, settings: settings);
        });
  }
}

class FirstRoute extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      child: Column(
        children: <Widget>[
          RaisedButton(
            child: Text("GO TO FRAGMENT TWO"),
            onPressed: () => Navigator.of(context).pushNamed("/second"),
          )
        ],
      ),
      decoration: BoxDecoration(color: Colors.green),
    );
  }
}

class SecondRoute extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      child: Column(
        children: <Widget>[
          RaisedButton(
            child: Text("GO TO FRAGMENT ONE"),
            onPressed: () => Navigator.of(context).pop(),
          )
        ],
      ),
      decoration: BoxDecoration(color: Colors.blue),
    );
  }
}

但是,这不符合我的要求.默认的导航器似乎仍在使用:打开SecondRoute并按下Android后退按钮后,它只会离开应用程序,而不仅仅是返回第一条路线.

This is however not working as I would like. The default Navigator seem to still be used : after opening the SecondRoute and pressing the Android back button, it just leaves the app instead of just going back to the first route.

我如何实现自己想要的?

How can I achieve what I want?

推荐答案

遵循onWillPop的文档:

Following the documentation of onWillPop:

  /// Called to veto attempts by the user to dismiss the enclosing [ModalRoute].
  ///
  /// If the callback returns a Future that resolves to false, the enclosing
  /// route will not be popped.
  final WillPopCallback onWillPop;

您的处理程序应指示不应关闭封闭路由,因此返回false将解决您的问题.

your handler should indicate that the enclosing route should not be closed, hence returning false will resolve your issue.

将您的处理程序更改为这项功能:

changing your handler to this works:

    onWillPop: () async {
      navigatorKey.currentState.maybePop();
      return false;
    },

这篇关于在Flutter中将嵌套导航器与WillPopScope一起使用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆