简体   繁体   中英

Dismiss keyboard on swipe back gesture in Flutter app

I am trying to dismiss the keyboard when the user swipes from the edge to pop route.

Currently the keyboard doesn't dismiss until the route is completely gone popped, messing up some of the other pages layout until it dismisses

I did try to use a WillPopScope to determine when the user was going to pop the route, but unfortunately this disables the swipe to pop functionality from iOS or the CupertinoPageRoute .

I just want to find out if there's anyway I can determine when the user swipes from the edge to pop or taps the back button on the appBar and dismiss the keyboard as they do so.

If possible, I am trying to dismiss keyboard as soon as they start swiping to pop, as it happens in many apps.

I am attaching attaching a gif showing the effect I'm trying to achieve.

滑动弹出隐藏键盘

You need to create a custom class extending NavigatorObserver , and pass an instance of it to the navigatorObservers property of your MaterialApp or CupertinoApp .

Within that custom class, you can override didStartUserGesture and didStopUserGesture , which will be called when the swipe gesture starts/ends. This should allow you to achieve the behavior you are looking for. Note that didStartUserGesture indicates the current route as well as the previous route, based on which you could add logic to determine whether the keyboard should be dismissed or not.

As suggested by Ovidiu

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

and in your Material App

MaterialApp(
  navigatorObservers: [DismissKeyboardNavigationObserver()],
)

This should come naturally and you shouldn't be directly concerned with that because actually, when you pop a route with the keyboard on, it should dismiss properly.

However, if you want to detect when the user starts swiping and dismiss the keyboard along with it and then pop the current route, you can easily achieve it by wrapping your screen widget with a GestureDetector like so:

 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...
      },

this is something i wrote to handle this issue. doesnt use any external packages, you would just wrap your content in the main function at the top.

 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(); }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM