user48956
user48956

Reputation: 15778

How to avoid duplicate events when combining GestureDetector and Listener in flutter

In the example below we have a tappable red container inside a green container.

Problem: when tapping the red container, BOTH the Listener and GestureDetector receive events, which is a mistake. (Only the topmost widget should get a tap event, when tapped. And only the green widget should get an event when tapped). If both wrapped with GestureDetector, only the topmost widget gets the event.

enter image description here

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Welcome to Flutter',
      home: Scaffold(
        appBar: AppBar(
          title: Text('Welcome to Flutter'),
        ),
        body: Center(
            child: Column(children: [
          // Parent-child -- two events when red is tapped
          GestureDetector(
            onTap: () {
              print("Green");
            },
            child: Container(
              color: Colors.green,
              width: 100.0,
              height: 100.0,
              child: Center(
                child: Listener(
                  behavior: HitTestBehavior.opaque,
                  onPointerDown: (_) {
                    print("Red");
                  },
                  child: Container(
                    color: Colors.red,
                    width: 50.0,
                    height: 50.0,
                  ),
                ),
              ),
            ),
          ),
        ])),
      ),
    );
  }
}

Upvotes: 4

Views: 1641

Answers (4)

user14631430
user14631430

Reputation:

as an option wrap Listener with GestureDetector to prevent event bubbling

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Welcome to Flutter',
      home: Scaffold(
        appBar: AppBar(
          title: Text('Welcome to Flutter'),
        ),
        body: Center(
            child: Column(children: [
              // Parent-child -- two events when red is tapped
              GestureDetector(
                onTap: () {
                  print("Green");
                },
                child: Container(
                  color: Colors.green,
                  width: 100.0,
                  height: 100.0,
                  child: Center(
                    child: GestureDetector(
                      behavior: HitTestBehavior.opaque,
                      onTap: (){},
                      child: Listener(
                        behavior: HitTestBehavior.opaque,
                        onPointerDown: (_) {
                          print("Red");
                        },
                        child: Container(
                          color: Colors.red,
                          width: 50.0,
                          height: 50.0,
                        ),
                      ),
                    ),
                  ),
                ),
              ),
            ])),
      ),
    );
  }
}

Upvotes: 2

Amit Kumar
Amit Kumar

Reputation: 307

There are special types of widgets which can do this thing easily.

 AbsorbPointer 
 IgnorePointer

Try this widget it will make your solution easy

Upvotes: 2

Saiful Islam
Saiful Islam

Reputation: 1269

If you want only a click event in both green and red separately than you can wrap your red Container() into a InkWell() widget.

See bellow code example

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Welcome to Flutter',
      home: Scaffold(
        appBar: AppBar(
          title: Text('Welcome to Flutter'),
        ),
        body: Center(
          child: Column(
            children: [
              // Parent-child -- two events when red is tapped
              GestureDetector(
                onTap: () {
                  print("Green");
                },
                child: Container(
                  color: Colors.green,
                  width: 100.0,
                  height: 100.0,
                  child: Center(
                    child: InkWell(
                      onTap: (){
                        print('red');
                      },
                      child: Container(
                        color: Colors.red,
                        width: 50.0,
                        height: 50.0,
                      ),
                    ),
                  ),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

Upvotes: 0

mkju
mkju

Reputation: 93

Using Stack can solve this problem:

Stack(
            alignment: Alignment.center,
            children: [
              InkWell(
                onTap: () {
                  print('green');
                },
                child: Container(
                  color: Colors.green,
                  width: 100.0,
                  height: 100.0,
                ),
              ),
              Listener(
                behavior: HitTestBehavior.translucent,
                onPointerDown: (_) {
                  print("Red");
                },
                child: Container(
                  color: Colors.red,
                  width: 50.0,
                  height: 50.0,
                ),
              ),
            ],
          )

,

Upvotes: 0

Related Questions