Fading Coder

One Final Commit for the Last Sprint

Home > Tools > Content

Controlling Touch Handling in Flutter with AbsorbPointer and IgnorePointer

Tools Apr 11 11

AbsorbPointer and IgnorePointer both prevent widgets in their subtree from reacting to pointer input (tap, drag, scroll). The difference lies in how they partiicpate in hit testing:

  • AbsorbPointer: removes its descendants from hit testing but is itself still hit. Encestors can receive the event; widgets behind it do not.
  • IgnorePointer: removes both itself and its descendants from hit testing. Events pass through to widgets behind it.

AbsorbPointer

Disable a group of interactive widgets without changing each handler. By default, absorbing is true, so child widgets won’t receive input.

AbsorbPointer(
  // true by default; set to false to re-enable input to children
  absorbing: true,
  child: Row(
    mainAxisSize: MainAxisSize.min,
    children: [
      ElevatedButton(
        onPressed: () => debugPrint('Pressed A'),
        child: const Text('A'),
      ),
      const SizedBox(width: 8),
      ElevatedButton(
        onPressed: () => debugPrint('Pressed B'),
        child: const Text('B'),
      ),
      const SizedBox(width: 8),
      ElevatedButton(
        onPressed: () => debugPrint('Pressed C'),
        child: const Text('C'),
      ),
    ],
  ),
)

Re-enable input by flipping the flag:

AbsorbPointer(
  absorbing: false,
  child: /* interactive subtree */
)

IgnorePointer

Similar usage, but the pointer is ignored for both the widget and its subtree; events hit widgets behind it.

IgnorePointer(
  // true by default
  ignoring: true,
  child: Row(
    mainAxisSize: MainAxisSize.min,
    children: [
      ElevatedButton(
        onPressed: () => debugPrint('Pressed X'),
        child: const Text('X'),
      ),
      const SizedBox(width: 8),
      ElevatedButton(
        onPressed: () => debugPrint('Pressed Y'),
        child: const Text('Y'),
      ),
      const SizedBox(width: 8),
      ElevatedButton(
        onPressed: () => debugPrint('Pressed Z'),
        child: const Text('Z'),
      ),
    ],
  ),
)

Hit Testing Difference in Practice

Two stacked boxes: a 200×200 red box and a centered 100×100 blue box. Each has its own pointer listener.

return SizedBox(
  height: 200,
  width: 200,
  child: Stack(
    alignment: Alignment.center,
    children: [
      Listener(
        onPointerDown: (_) => debugPrint('tap: RED'),
        child: Container(color: Colors.red),
      ),
      Listener(
        onPointerDown: (_) => debugPrint('tap: BLUE'),
        child: Container(
          width: 100,
          height: 100,
          color: Colors.blue,
        ),
      ),
    ],
  ),
);
  • Tapping the blue square printts:
tap: BLUE
  • Tapping the red area outside the blue square prints:
tap: RED

Wrap blue with AbsorbPointer

The outer Listener surrounds AbsorbPointer; the inner Listener is inside it. The inner hendler will not fire, but the outer one still will.

return SizedBox(
  height: 200,
  width: 200,
  child: Stack(
    alignment: Alignment.center,
    children: [
      Listener(
        onPointerDown: (_) => debugPrint('tap: RED'),
        child: Container(color: Colors.red),
      ),
      Listener(
        onPointerDown: (_) => debugPrint('tap: BLUE (outer parent)'),
        child: AbsorbPointer(
          child: Listener(
            onPointerDown: (_) => debugPrint('tap: BLUE (inner child)'),
            child: Container(
              width: 100,
              height: 100,
              color: Colors.blue,
            ),
          ),
        ),
      ),
    ],
  ),
);
  • Tapping the blue square prints:
tap: BLUE (outer parent)

The AbsorbPointer itself participates in hit testing and consumes the event for its subtree; the ancestor Listener still receives it.

Replace with IgnorePointer

Change AbsorbPointer too IgnorePointer in the previous snippet (keeping the same structure):

IgnorePointer(
  child: Listener(
    onPointerDown: (_) => debugPrint('tap: BLUE (inner child)'),
    child: Container(
      width: 100,
      height: 100,
      color: Colors.blue,
    ),
  ),
)
  • Tapping the blue square prints:
tap: RED

IgnorePointer removes itself and its subtree from hit testing, so the touch goes through to the red box behind it.

Typical Use Cases

  • Temporarily disable or enable a set of controls (buttons, inputs, scrollables) with a single flag.
  • Lock the entire screen or a section during a blocking operation (e.g., while a network request is in progress).
  • Allow touches to pass through overlay UIs (e.g., transparent hints or tutorials) to underlying content using IgnorePointer.
  • Maintain parent-level gesture handling while suppressing child interactions using AbsorbPointer.

Related Articles

Efficient Usage of HTTP Client in IntelliJ IDEA

IntelliJ IDEA incorporates a versatile HTTP client tool, enabling developres to interact with RESTful services and APIs effectively with in the editor. This functionality streamlines workflows, replac...

Installing CocoaPods on macOS Catalina (10.15) Using a User-Managed Ruby

System Ruby on macOS 10.15 frequently fails to build native gems required by CocoaPods (for example, ffi), leading to errors like: ERROR: Failed to build gem native extension checking for ffi.h... no...

Resolve PhpStorm "Interpreter is not specified or invalid" on WAMP (Windows)

Symptom PhpStorm displays: "Interpreter is not specified or invalid. Press ‘Fix’ to edit your project configuration." This occurs when the IDE cannot locate a valid PHP CLI executable or when the debu...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.