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 totrue
.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
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 totrue
.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
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
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
That's the difference between those two.