Flutter:在 iOS 和 Android 中禁用滑动导航返回

Posted

技术标签:

【中文标题】Flutter:在 iOS 和 Android 中禁用滑动导航返回【英文标题】:Flutter: Disable Swipe to Navigate Back in iOS and Android 【发布时间】:2018-08-16 03:06:32 【问题描述】:

我是 Flutter 开发的新手,当你有一个导航抽屉并且当你滑动打开它时,发现它在 ios 中有点令人沮丧,当你滑动打开它时,它会执行 Navigation.of(context).pop()。我想在 iOS 中禁用这种“滑动弹出”行为。我一直在阅读文档,但运气不佳。

我确实看到了被称为 WillPopScope 的东西,它似乎可以解决问题 (github issue for it here),但我不能 100% 确定这是否是“正确”的方法(它似乎太复杂了...应该更容易...就像根应用程序上的设置一样)。

【问题讨论】:

【参考方案1】:

WillPopScope 正确的方法。

(看起来太复杂了……应该更简单……就像根应用程序上的设置)。

这并不复杂。这是一个班轮:

WillPopScope(
  onWillPop: () async => false,
  child: <children here>
)

配置文件会使事情变得更复杂,因为它更难阅读和维护。

请记住,在 Flutter 中,一切都是小部件,而不仅仅是其中的一半。身份验证,配置,一切。

【讨论】:

嘿@Darky 我们成为朋友了吗:P 我实际上找到了一个巧妙的方法来做到这一点......我即将发布我的答案。 @rémi-rousselet:你知道为什么返回 true 而不是 false 也可以防止弹出吗? 我只是将“return false”更改为“return true”,这样硬件和应用程序栏的后退按钮就可以在仍然禁用向后滑动的情况下工作。 @Benjamin @Max 等什么? return true 应该相当于不取消弹出。它阻止 IOS 滑动的事实很可能是一个错误。 @RémiRousselet:你很可能是对的。我的问题是修辞性的 ;-)【参考方案2】:

我还有一点要补充。我只是在解决这个问题,但我还需要我的用户能够通过按 AppBar 上的“本机”后退按钮返回(因为这个原因不想重新实现 AppBar),我发现了这个利基小标志: userGestureInProgress 在 Navigator 对象上,所以我使用的(假设是首选方式)是:

onWillPop: () async 
    if (Navigator.of(context).userGestureInProgress)
      return false;
    else
      return true;
  ,

【讨论】:

不适用于 android。 userGestureInProgress 总是返回 false...【参考方案3】:

MaterialPageRoute 有一个名为 fullscreenDialog 的参数,默认设置为 false。如果为 true,您的页面动画会有所不同,并且在 iOS 上滑动返回将被禁用。

示例用法:

 Navigator.of(context).push(
        MaterialPageRoute(builder: (_) => HomePage(), fullscreenDialog: true));

在这里查看一些讨论:https://github.com/flutter/flutter/issues/14203

【讨论】:

这对我来说非常适合条款和条件页面。谢谢。【参考方案4】:

你可以在你的小部件构建中试试这个:

@override
  Widget build(BuildContext context) 
    return WillPopScope(//forbidden swipe in iOS(my ThemeData(platform: TargetPlatform.iOS,)
      onWillPop: ()async 
        if (Navigator.of(context).userGestureInProgress)
          return false;
        else
          return true;
      ,
      child: <your child>,
    );
  

【讨论】:

onWillPop 可以这样短 onWillPop: () async =&gt; !(Navigator.of(context).userGestureInProgress),【参考方案5】:

好的,正如@Darky 所说,WillPopScope 是一个完全可以接受的答案,但是,如果您想全面禁用它,您实际上可以执行以下操作。

在 xcode 中打开你的项目,找到 AppDelegate.swift 并添加以下内容:

let controller: FlutterViewController
    = window?.rootViewController as! FlutterViewController;
controller.navigationController?
    .interactivePopGestureRecognizer?.isEnabled = false;

【讨论】:

呃!我觉得这太可怕了。你永远不应该触摸 ios/android 文件夹,而只能在 dart 中编写代码。如果你真的想在任何地方禁用它,那么它应该用 dart 编写并传递给MaterialAppWidgetApp 哦,我同意,应该有一个设置或属性可以简单地传递到您的 MaterialApp 的根目录中,但可惜没有。 :'( 修改flutter的源码。你甚至不需要离开你的 IDE。您也可以放置断点、编辑和热重载颤振源。甚至无需离开您的应用程序。 您的解决方法基本上是将一切包装在WillPopScope中。应该很容易【参考方案6】:

我有一个类似的问题,我想阻止滑动返回导航(默认弹出功能)。这段代码帮助解决了这个问题。

@override
Widget build(BuildContext context) 
    return WillPopScope(
      onWillPop: () async => false,
      child: Scaffold(
        body: Center(
          child: Text('Example'),
        ),
      ),
    );
  

此代码现在阻止了 iOS 和 Android 的后退导航(默认后退按钮),而这正是我想要的。希望这会有所帮助。

【讨论】:

【参考方案7】:

我不太确定你想要实现什么,但大多数时候人们想要摆脱后台功能,因为他们不想让用户控制身份验证机制。例如,在用户登录后,您不希望他们通过按后退按钮(或在 iOS 中向后滑动)导航到登录页面。一个潜在的解决方案是使用pushNamedAndRemoveUntil

Future&lt;T&gt; pushNamedAndRemoveUntil&lt;T extends Object&gt;(BuildContext context, String newRouteName, RoutePredicate predicate)

将给定名称的路由推送到最常用的导航器上 紧紧包围给定的上下文,然后删除所有以前的 路由直到 predicate 返回 true。

示例代码: pushNamedAndRemoveUntil(context, '/home', ModalRoute.withName('/home'));

注意:在一定程度上使用这种方法,因为你可能会弄乱你的导航历史。

【讨论】:

这并不能完全解决所有情况......即使使用左侧面板/抽屉滑动打开手势,它也会偶尔向后导航【参考方案8】:

返回按钮滑动手势(iOS)被按下时,您将在onWillPop收到回调, 它返回一个Future。如果Future 返回true,则弹出屏幕(即导航到上一个屏幕),如果为false,则不会返回。

Widget build(BuildContext context) 
    return WillPopScope(
      onWillPop: () 
        return Future.value(false);
      ,
      child: Scaffold(
        appBar: AppBar(title: Text("Second Screen"),),
        body: Center(

如果你想根据条件弹出屏幕然后声明

bool shouldPop = true; // change this using setState() inside build on the requirement. 

  onWillPop: () 
        return Future.value(shouldPop? true: false);
      ,

【讨论】:

以上是关于Flutter:在 iOS 和 Android 中禁用滑动导航返回的主要内容,如果未能解决你的问题,请参考以下文章

Flutter 在 facebook 应用程序 android 和 ios 中打开 facebook 链接

将 Android 和 iOS 库导入 Flutter 项目

如何在开发过程中同时使用 Android 和 IOS 模拟器来测试我的 Flutter 应用程序?

如何使用 Flutter 处理应用程序生命周期(在 Android 和 iOS 上)?

使用flutter项目创建原生ios框架(.framework)和Android jar

如何在 Flutter(Android 和 Ios)中实现与 WebRTC 的电话会议视频聊天