【问题标题】:Dismiss keyboard on swipe back gesture in Flutter app在 Flutter 应用程序中以向后滑动手势关闭键盘
【发布时间】:2019-12-07 07:30:16
【问题描述】:

当用户从边缘滑动到弹出路径时,我试图关闭键盘。

目前键盘在路由完全弹出之前不会关闭,在它关闭之前会弄乱其他一些页面布局

我确实尝试使用WillPopScope 来确定用户何时要弹出路线,但不幸的是,这会禁用 iOS 或 CupertinoPageRoute 的滑动弹出功能。

我只是想知道我是否可以确定用户何时从边缘滑动弹出或点击 appBar 上的后退按钮并在他们这样做时关闭键盘。

如果可能,我会尝试在键盘开始滑动弹出时立即关闭键盘,这在许多应用中都会发生。

我正在附加一个 gif,显示我想要达到的效果。

【问题讨论】:

  • 我不确定,但这可能会有所帮助 -: FocusScope.of(context).unfocus();
  • 是的,我知道。我的问题是,当拖动弹出开始时我该怎么做。在点击按钮或点击屏幕上的任何位置时使键盘失焦不是问题,在拖动到弹出时让它这样做是

标签: flutter dart flutter-navigation


【解决方案1】:

您需要创建一个扩展NavigatorObserver 的自定义类,并将其实例传递给MaterialAppCupertinoAppnavigatorObservers 属性。

在该自定义类中,您可以覆盖didStartUserGesturedidStopUserGesture,它们将在滑动手势开始/结束时调用。这应该允许您实现您正在寻找的行为。请注意,didStartUserGesture 表示当前路由以及之前的路由,您可以在此基础上添加逻辑来确定是否应关闭键盘。

【讨论】:

  • 这可以工作,但我如何从 navigationObserver 访问文本字段的焦点以便能够关闭它们?
  • 标记为答案,因为它确实允许我想要的。对于任何寻找的人,请检查我对我使用的课程的回答。
【解决方案2】:

根据 Ovidiu 的建议

class DismissKeyboardNavigationObserver extends NavigatorObserver {
  @override
  void didStartUserGesture(Route route, Route previousRoute) {
    SystemChannels.textInput.invokeMethod('TextInput.hide');
    super.didStartUserGesture(route, previousRoute);
  }
}

在您的 Material 应用中

MaterialApp(
  navigatorObservers: [DismissKeyboardNavigationObserver()],
)

【讨论】:

  • 能否分享一下截取的代码,我们如何在带有 textField 的页面上使用它?
【解决方案3】:

这应该是自然而然的,你不应该直接关心它,因为实际上,当你在键盘上弹出一条路线时,它应该正确地关闭。

但是,如果您想检测用户何时开始滑动并关闭键盘,然后弹出当前路线,您可以通过使用GestureDetector 包裹您的屏幕小部件来轻松实现它,如下所示:

 Widget build(BuildContext context) {
    double dragStart = 0.0;
    return GestureDetector(
      onHorizontalDragStart: (details) => dragStart = details.globalPosition.dx,
      onHorizontalDragUpdate: (details) {
        final double screenWidth = MediaQuery.of(context).size.width;

        // Here I considered a back swipe only when the user swipes until half of the screen width, but you can tweak it to your needs.
        if (dragStart <= screenWidth * 0.05 && details.globalPosition.dx >= screenWidth) {
          FocusScope.of(context).unfocus();
        }
       child: // Your other widgets...
      },

【讨论】:

  • 现在就试试。默认实现的问题是它不会关闭键盘,直到页面完全消失,这是一种奇怪的、不需要的行为。理想情况下,键盘应该留在那个 pageRoute 上,或者在弹出时消失。另外,有没有办法让每个带有 textField 的页面都有这种行为?
  • 这适用于任何会启动键盘的路线,并且一旦您开始向后滑动它就会被关闭,我相信这就是您正在寻找的。​​span>
  • 不幸的是,这不起作用。从 PageRoute 弹出的滑动优先于 GestureDetector。它可以从屏幕左侧工作,但不能在用户从滑动到关闭的边缘工作。
  • 那是因为我让它只有在一些偏移量(屏幕宽度的 15%)后才能工作。我已经更新了我的答案。
  • 它也不起作用。现在我真的不知道 GestureDetector 在做什么,但它仍然不会关闭 dragToPop 上的键盘。我附上了一个带有预期行为的 GIF。如果用户选择不弹出屏幕并松开滑动弹出,我不介意不重新聚焦,但我确实需要它在拖动开始时立即关闭键盘。 CupertinoPageRoute 中的 isPopGestureInProgress 函数可能有一个解决方案,但我还没有找到成功使用它的方法。
【解决方案4】:

这是我为处理这个问题而写的。不使用任何外部包,您只需将内容包装在顶部的 main 函数中。

Widget swipeOffKeyboard(BuildContext context, {Widget? child}) {
  return Listener(
    onPointerMove: (PointerMoveEvent pointer) {
      disKeyboard(pointer, context);
    },
    child: child, // your content should go here
  );
}

void disKeyboard(PointerMoveEvent pointer, BuildContext context) {
  double insets = MediaQuery.of(context).viewInsets.bottom;
  double screenHeight = MediaQuery.of(context).size.height;
  double position = pointer.position.dy;
  double keyboardHeight = screenHeight - insets;
  if (position > keyboardHeight && insets > 0) FocusManager.instance.primaryFocus?.unfocus();
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-06
    • 1970-01-01
    • 2015-05-25
    • 1970-01-01
    • 2015-10-22
    • 2020-02-23
    相关资源
    最近更新 更多