Fading Coder

One Final Commit for the Last Sprint

Home > Tools > Content

Controlling Touch Handling in Flutter with AbsorbPointer and IgnorePointer

Tools 1

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.