flutterdartgesturedetectorevent-behaviour

GestureDetector with HitTestBehavior.opaque not work properly to hide keyboard screen


I want to hide screen keyboard by onTap outside TextField or anywhere on screen. Then i wrap my Scaffold with GestureDetector like below. i already try both with onTap and onTapDown.

 GestureDetector(
  behavior: HitTestBehavior.opaque,
  onTapDown: (_) {
    printLog("hide keyboard ${_.localPosition}");
    FocusManager.instance.primaryFocus?.unfocus();
    },
  child: Scaffold()

Everything work fine on simple widget (small amount of widget ). But when i have much widget rendered, the function to hide keyboard only called sometimes. not every action ontap Happend on my screen.

eg in my scaffold body:

ListView.builder(
    itemCount: 50,
    itemBuilder: ((context, index) => GestureDetector(
          onTap: () {
            printLog("tap on card");
          },
          child: Container(
            margin: const EdgeInsets.symmetric(vertical: 3),
            height: 60,
            color: Colors.blueGrey,
          ),)))

here the console log. as we can see (line 4) , the print('[Debug] hide keyboard Offset()') do not called every onTap() happend on my screen.

I/flutter (15284): [Debug] hide keyboard Offset(281.5, 330.2)
(2)I/flutter (15284): [Debug] tap on card
I/flutter (15284): [Debug] hide keyboard Offset(253.5, 292.0)
(3)I/flutter (15284): [Debug] tap on card   => i tapped 3 times on my card 
I/flutter (15284): [Debug] tap on card   => until the 4th tap, keybord not hide
I/flutter (15284): [Debug] hide keyboard Offset(186.2, 279.3)
I/flutter (15284): [Debug] tap on card

but when i do longpress on my card, the function hide keyboard always will be called. i assume there is a delay on GestureDetector while catching the onTap. so user need to tap longer than usual. But its not good thing, because i cant tell the user to press longer on screen everytime use the app. .

.

what i want to achieve is, every clicking outside of my Textfield, it should called hide keyboard function without delayed.


Solution

  • Update the latest version

    we can use a new property named onTapOutside. No need to wrap all widgets with GestureDetector

    TextFormField(
      onTapOutside: (event) =>
          FocusManager.instance.primaryFocus?.unfocus(),
      controller: _ctrl,
    

    old answer

    reff: https://stackoverflow.com/a/53063398/12838877

    so i change the GestureDetector to Listener . it more faster.

    documentation said:

    Rather than listening for raw pointer events, consider listening for higher-level gestures using GestureDetector.

    and its works fine as expected now.

     @override
      Widget build(BuildContext context) {
        return Listener(
          behavior: HitTestBehavior.opaque,
          onPointerDown: (_) {
            printLog("hide keyboard ${_.localPosition}");
            FocusManager.instance.primaryFocus?.unfocus();
          },
          child: Scaffold()