11

I am trying to detect a tap on the screen. I've tried multiple variation of using the GestureDetector but that just leads to the app detecting tap on the child element and not the screen.

Here is the code:

class QQHome extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        primaryColor: Colors.blueGrey,
      ),
      home: Scaffold(
        appBar: AppBar(
          centerTitle: true,
          title: Text('QuoteQuota'),
        ),
        body: GestureDetector(
          onTap: () => print('Tapped'),
          child: QQBody(),
        ),
      ),
    );
  }
}

class QQBody extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Text(
        'Hello, World!'
      ),
    );
  }
}

Output: "tapped" printed when I click "Hello, World!".

Expected Output: "tapped" printed when I click anywhere on the screen with Text in the Center.

How do I do this?

Nachiketa Vadera
  • 125
  • 1
  • 1
  • 6

6 Answers6

23

Use GestureDetector's behavior property and pass HitTestBehavior.opaque to it, which recognizes entire screen and detects the tap when you tap anywhere on the screen.

body: GestureDetector(
          behavior: HitTestBehavior.opaque,
          onTap: () => print('Tapped'),
          child: QQBody(),
        ),

Hope this answers your question.

Darshan
  • 10,550
  • 5
  • 49
  • 61
  • Hi @Darshan, I have a similar sort of requirement. I want the QQBody to be displayed when I tap anywhere on the screen instead of printing 'Tapped' within the console. I'm new to Flutter and not sure how can I achieve that. I did try replacing print with QQBody but it didn't work. Could you please suggest what needs to be done. Thanks in advance! – xpetta May 07 '20 at 10:27
3

Like Darshan said, you can trigger Tap by wrapping the body inside a Gesture detector like this...

body: GestureDetector(
          behavior: HitTestBehavior.opaque,
          onTap: () => print('Tapped'),
          child: QQBody(),
        ),

Also in some cases, you may need to avoid trigger clicking on other widgets while tapping anywhere in body. That can be solved by using IgnorePointer Widget

body: GestureDetector(
      behavior: HitTestBehavior.opaque,
      onTap: () {
        print('This will click');
      },

      // -------- No Widget below tree will be trigger click.

      child: IgnorePointer(
        ignoring: ClassLibrary.selected != null ? true : false,
        child: TabBarView(
          children: [
                   ...
MBK
  • 2,589
  • 21
  • 25
  • What do you do if `QQBody` isn't full screen but is just something in the center of a blank screen? How do you go about capturing a gesture anywhere on the screen then? – claudekennilol May 30 '23 at 19:07
1

@Darshan is a correct answer but I want to add something to it. I wanted a trigger whenever the screen is touched and onTap only reacts to a tap (no slide). However that behaviour can be achieved bij adding onTapCancel

body: GestureDetector(
          behavior: HitTestBehavior.opaque,
          onTap: () => print('Tapped'),
          onTapCancel: () => print('Touched but not tapped'),
          child: QQBody(),
        ),
Renza Polza
  • 87
  • 1
  • 8
0

Please use below code--

class QQHome extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        primaryColor: Colors.blueGrey,
      ),
      home: Scaffold(
        appBar: AppBar(
          centerTitle: true,
          title: Text('QuoteQuota'),
        ),
        body: GestureDetector(
          onTap: () => print('Tapped'),

          child: Container(
          height : MediaQuery.of(context).size.height,
          width : MediaQuery.of(context).size.width,
),
        ),
      ),
    );
  }
}
Flutterian
  • 1,761
  • 1
  • 21
  • 47
0

You can use Stack: put layers on top of each other. The good thing about Stack is you can arrange stack order as you want. If you want to do something as the screen is touched, and do something else if a button on the screen is touched, you can easily do it with stack by putting the button on top of GestureDetector.

The following is your example:

class QQHome extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        primaryColor: Colors.blueGrey,
      ),
      home: Scaffold(
        appBar: AppBar(
          centerTitle: true,
          title: Text('QuoteQuota'),
        ),
        body: Stack(
          // Bottom to Top order
          children: <Widget> [
            QQBody(),
            GestureDetector(
              onTap: () => print('Tapped'),
            ),
          ]
        ),
      ),
    );
  }
}

class QQBody extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Text(
        'Hello, World!'
      ),
    );
  }
}
Yoju
  • 179
  • 2
  • 4
  • That does work but nothing else on the screen can be tapped anymore because you have the GestureDetector on top. – Anteino Jun 23 '22 at 10:31
0

You can do this very easy with TapRegion

TapRegion(
    onTapInside: (event) => print('tapped'),
    child: SomeChild(),
)

It also have another useful method called onTapOutside in case you need that too.

Sh1d0w
  • 9,340
  • 3
  • 24
  • 35