Flutter - Using IgnorePointer & AbsorbPointer Examples

This tutorial shows you how to use IgnorePointer and AbsorbPointer in Flutter and what's the difference between those two.

Nowadays applications use touch input from users. What if you want to disable the touch in a certain area or in other word, you want to make the touch pointer has no effect. In Flutter, you can use IgnorePointer or AbsorbPointer. Below I'm going to show you how to use them and the difference behavior between the widgets.

Using IgnorePointer

Below is the constructor of IgnorePointer along with its properties:

  const IgnorePointer({
    Key key,
    this.ignoring = true,
    this.ignoringSemantics,
    Widget child,
  })

Properties:

  • Key key: The widget key, used to control if it's should be replaced.
  • bool ignoring: Whether this widget is ignored during hit testing. Defaults to true.
  • bool ignoringSemantics: Whether the semantics of this widget is ignored when compiling the semantics tree.
  • Widget child: The widget to be rendered.

If ignoring value is true, any click inside the widget will be ignored.

Using IgnorePointer is very simple, just wrap the widget you want to render inside an IgnorePointer widget. As the default value is true, any touch will be ignored if you don't pass ignoring parameter on the constructor.

  IgnorePointer(
    ignoring: _ignoring,
    child: MyWidget(),
  )

Let's take a look at the below example. The IgnorePointer wraps a RaisedButton and a TextField. There's also a button for toggling _ignoring variable value which is passed as ignoring attribute.

  class _IgnorePointerAppState extends State<_IgnorePointerApp> {
    bool _ignoring = false;
  
    @override
    Widget build(BuildContext context) {
      return Scaffold(
        appBar: AppBar(
          title: Text('Woolha.com Flutter Tutorial'),
        ),
        body: Builder(
          builder: (context) => Center(
            child: Padding(
              padding: EdgeInsets.all(15.0),
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: <Widget>[
                  IgnorePointer(
                    ignoring: _ignoring,
                    child: Column(
                      children: <Widget>[
                        RaisedButton(
                          child: Text('Press the button'),
                          onPressed: () {
                            Scaffold.of(context).showSnackBar(
                                SnackBar(content: Text('Button is pressed'))
                            );
                          },
                        ),
                        TextField(),
                      ],
                    ),
                  ),
                  Row(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: <Widget>[
                      Text('Ignore Pointer?'),
                      Switch(
                          value: _ignoring,
                          onChanged: (bool value) {
                            setState(() {
                              _ignoring = value;
                            });
                          }),
                    ],
                  ),
                ],
              ),
            ),
          ),
        ),
      );
    }
  }

If you run the above code and switch the toggle on, you won't be able to click the RaisedButton or the TextField. However, if the TextField's cursor is active, you can still continue to type using the keyboard.

Output

Flutter - IgnorePointer

 

Using AbsorbPointer

Below is the constructor of AbsorbPointer along with its properties:

  const AbsorbPointer({
    Key key,
    this.absorbing = true,
    Widget child,
    this.ignoringSemantics,
  })

Properties:

  • Key key: The widget key, used to control if it's should be replaced.
  • bool absorbing: Whether this widget absorbs pointers during hit testing. Defaults to true.
  • bool ignoringSemantics: Whether the semantics of this widget is ignored when compiling the semantics tree.
  • Widget child: The widget to be rendered.

If absorbing value is true, any click inside the widget will be absorbed. If you don't pass absorbing parameter, it will use the default value (true) which causes any pointer inside the widget will be absorbed.

The usage of AbsorbPointer is similar to IgnorePointer, just change ignoring property with absorbing.

  IgnorePointer(
    ignoring: _ignoring,
    child: MyWidget(),
  )

Here's a similar example that uses AbsorbPointer

  class _AbsorbPointerAppState extends State<_IgnorePointerApp> {
    bool _absorbing = false;
  
    @override
    Widget build(BuildContext context) {
      return Scaffold(
        appBar: AppBar(
          title: Text('Woolha.com Flutter Tutorial'),
        ),
        body: Builder(
          builder: (context) => Center(
            child: Padding(
              padding: EdgeInsets.all(15.0),
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: <Widget>[
                  AbsorbPointer(
                    absorbing: _absorbing,
                    child: Column(
                      children: <Widget>[
                        RaisedButton(
                          child: Text('Press the button'),
                          onPressed: () {
                            Scaffold.of(context).showSnackBar(
                                SnackBar(content: Text('Button is pressed'))
                            );
                          },
                        ),
                        TextField(),
                      ],
                    ),
                  ),
                  Row(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: <Widget>[
                      Text('Absorb Pointer?'),
                      Switch(
                          value: _absorbing,
                          onChanged: (bool value) {
                            setState(() {
                              _absorbing = value;
                            });
                          }),
                    ],
                  ),
                ],
              ),
            ),
          ),
        ),
      );
    }
  }

Output

Flutter - AbsorbPointer

 

Difference Between IgnorePointer and AbsorbPointer

On the above examples, the behavior of IgnorePointer and AbsorbPointer look similar. So, what's the difference between those two widgets. The below examples make the difference obvious.

Now, we have a Stack consisting of two buttons with exactly same position. Button 2 is above Button 1. Button2 is wrapped inside IgnorePointer. When a button is clicked, a SnackBar will be shown.

 child: new Stack(
    alignment: AlignmentDirectional.center,
    children: [
      RaisedButton(
        child: Text('Button 1'),
        onPressed: () {
          Scaffold.of(context).showSnackBar(
              SnackBar(content: Text('Button 1 is pressed'))
          );
          print('Button 1 is pressed');
        },
      ),
      IgnorePointer(
        ignoring: _ignoring,
        child: RaisedButton(
          child: Text('Button 2'),
          onPressed: () {
            Scaffold.of(context).showSnackBar(
                SnackBar(content: Text('Button 2 is pressed')));
            print('Button 2 is pressed');
          },
        ),
      ),
    ],
  ),

If ignoring is set to true and you click on the button, you will see the SnackBar from Button 1. That means the pointer is ignored on Button 2, but the pointer is detected on Button 1.

Output

Flutter - IgnorePointer

 

Below is another example that generates the same visual output as the previous code, but with AbsorbPointer instead.

 child: new Stack(
    alignment: AlignmentDirectional.center,
    children: [
      RaisedButton(
        child: Text('Button 1'),
        onPressed: () {
          Scaffold.of(context).showSnackBar(
              SnackBar(content: Text('Button 1 is pressed'))
          );
          print('Button 1 is pressed');
        },
      ),
      AbsorbPointer(
        absorbing: _absorbing,
        child: RaisedButton(
          child: Text('Button 2'),
          onPressed: () {
            Scaffold.of(context).showSnackBar(
                SnackBar(content: Text('Button 2 is pressed')));
            print('Button 2 is pressed');
          },
        ),
      ),
    ],
  ),

If absorbing is set to true and you click on the button, neither Button 1 nor Button 2 will trigger the SnackBar. That means the pointer is absorbed and not passed to the layers below AbsorbPointer.

Output

Flutter - AbsorbPointer

 

That's the difference between those two.