1

I'm trying to wrap my whole app in a widget that will prevent touch event being passed down through the view hierarchy based on some condition. I already have a WrapperlifecycleListener in place:

@override
  Widget build(BuildContext context) {
    return WrapperAppLifecycleListener(
      child: Listener(
        onPointerDown: (_) {
          //other stuff I do
        },
        child: MyApp(),
      ),
    );
  }

I was expecting to be able to do something like this:

 onPointerDown: (_) {
          if(passThrough){
              return true;
          } else {
              return false;
          }
        },

but all the widget I found so far all have void as return type of their callbacks, is there any widget that does something like that?

EDIT: the condition changes when the user interact with the app itself, so IgnorePointer or AbsorbPointer would not work in this case. To be clearer consider a case where I want to disable all touch inputs after a touch input, so hypotetically:

@override
  Widget build(BuildContext context) {
    return WrapperAppLifecycleListener(
      child: Listener(
        
        onPointerDown: (_) {
          
              if(absorb){
                  return false;
              } else {
                  return true;
              }
          absorb = true;
          Future.delayed(Duration(seconds:2)).then((value) => absorb = false);
        },
        child: MyApp(),
      ),
    );
  }
jack_the_beast
  • 1,838
  • 4
  • 34
  • 67
  • By "touch events" you mean basically all input events? – nvoigt Aug 16 '21 at 07:26
  • I would recommend using something like `IgnorePointer()`. It has a `ignore` field that can be set to true or false, which will avoid any of its child from receiving hit events. – SupremeDeity Aug 16 '21 at 07:29
  • @nvoigt well, the focus are single taps but I could work with any event – jack_the_beast Aug 16 '21 at 07:29
  • @SupremeDeity I looked into that, the problem is that I also need to know when the tap happens at that level, and IgnorePointer doesn't seem to provide that unless I'm missing something. sorry if that wasn't clear I'll update my question – jack_the_beast Aug 16 '21 at 07:31
  • The only other thing i can think of is using something like `Provider`, then use the `onTap` on something like `GestureDetector`, do whatever checking you need and ignore the event if the Provider's value is false – SupremeDeity Aug 16 '21 at 07:36
  • 1
    The above is only for when you need to detect events on every level, would still recommend a `AbsorbPointer()` if you only need to detect click event at the parent level. – SupremeDeity Aug 16 '21 at 07:39

2 Answers2

1

What I ended up doing while I search for a better solution is:

class GestureInterceptor extends StatefulWidget {
  final Widget child;

  const GestureInterceptor({required this.child});

  @override
  _GestureInterceptorState createState() => _GestureInterceptorState();
}

class _GestureInterceptorState extends State<GestureInterceptor> {
  var absorbTaps = false;

  @override
  Widget build(BuildContext context) {
    return AbsorbPointer(
      absorbing: absorbTaps,
      child: WrapperAppLifecycleListener(
        child: Listener(
          onPointerDown: (_) {
           
            setState(() {
              absorbTaps = true;
            });
            Future.delayed(Duration(milliseconds: 400))
                .then((value) => setState(() {
                      absorbTaps = false;
                    }));
          },
          child: widget.child,
        ),
      ),
    );
  }
}
jack_the_beast
  • 1,838
  • 4
  • 34
  • 67
0

It seem you want either an AbsorbPointer (link) or IgnorePointer (link) widget in your tree. Both can be controlled via a boolean property.

For an explanation on the difference, see Flutter AbsorbPointer vs IgnorePointer difference

nvoigt
  • 75,013
  • 26
  • 93
  • 142