In this post we will build a widget that can disable multi touch on a widget in Flutter app.
Introduction
Sometimes, you might need to disable multi touch or tap on a widget in your Flutter application. For example there is a list of items and only one of those items should be clickable at once. You do not want users to tap or touch with three fingers simultaneously and select three items at once.
Basically, you want to prevent users from multi-tapping or multi-touching.

So how can we prevent multi tap or multi touch gestures?
Setup
Let’s say we have a simple list of items that creates a list widget as shown in the .gif above:
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
class MyList extends StatelessWidget {
List<String> myList = [
"January",
"February",
"March",
"April",
"June",
"July",
"August"
];
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: ListView.builder(
shrinkWrap: true,
itemCount: myList.length,
physics: ClampingScrollPhysics(),
itemBuilder: (BuildContext cxtListBuilder, int itemIdx) {
return ListTile(
title: Text(myList[itemIdx]),
onTap: () => print('tapped'),
);
})));
}
}
Currently, each item on the list like name of months supports multi tap gesture. We want to prevent this action.
Creating A Custom Gesture Recognizer
Flutter allows creating custom gesture recognizer widgets with the help of GestureRecognizer
base class. There are already two abstract implementations of this class for multi tap and single tap gestures.
Since we are looking to implement a single tap gesture, we will create an implementation class for OneSequenceGestureRecognizer.
Implementation For Single Touch
Start by creating a custom widget that can allow it’s child widgets to have single touch gesture only.
class SingleTouchRecognizerWidget extends StatelessWidget {
final Widget child;
SingleTouchRecognizerWidget({this.child});
@override
Widget build(BuildContext context) {
// TODO: implement build
return null;
}
}
In it’s build function, we will return a gesture detector widget that supports single touch gesture only. So, let’s create another class called _SingleTouchRecognizer
for this purpose
class _SingleTouchRecognizer extends OneSequenceGestureRecognizer {
@override
// TODO: implement debugDescription
String get debugDescription => null;
@override
void didStopTrackingLastPointer(int pointer) {
// TODO: implement didStopTrackingLastPointer
}
@override
void handleEvent(PointerEvent event) {
// TODO: implement handleEvent
}
}
We will come back to the implementation of _SingleTouchRecognizer
later. For now, let’s complete setup of SingleTouchRecognizerWidget
widget.
class SingleTouchRecognizerWidget extends StatelessWidget {
final Widget child;
SingleTouchRecognizerWidget({this.child});
@override
Widget build(BuildContext context) {
return RawGestureDetector(
gestures: <Type, GestureRecognizerFactory>{
_SingleTouchRecognizer: GestureRecognizerFactoryWithHandlers<_SingleTouchRecognizer>(
() => _SingleTouchRecognizer(),
(_SingleTouchRecognizer instance) {},
),
},
child: child,
);
}
}
The build method now returns a RawGestureDetector
that handles gestures from _SingleTouchRecognizer
class.
Next, we need to implement the methods in our recognizer class.
We start by overriding addAllowedPointer
method of GestureRecognizer.
class _SingleTouchRecognizer extends OneSequenceGestureRecognizer {
int _p = 0;
@override
void addAllowedPointer(PointerDownEvent event) {
//first register the current pointer so that related events will be handled by this recognizer
startTrackingPointer(event.pointer);
//ignore event if another event is already in progress
if (_p == 0) {
resolve(GestureDisposition.rejected);
_p = event.pointer;
} else {
resolve(GestureDisposition.accepted);
}
}
...
Here, the startTrackingPointer
method registers the related events to be handled by the recognizer. Then resolve
function is responsible for ensuring if the touch event should be allowed to be continued or not.
Parameters For Resolve
If we pass GestureDisposition.rejected
, the current touch event is not resolved. So this touch event will be passed down and allowed to continue. However if GestureDisposition.accepted
is passed, then touch event is resolved and no other events are called past this.
We want to resolve a tap event if there is already another touch event created preventing multi-tap/multi-touch.
Finally, we reset the value of control variable _p
via the handleEvent
function.
...
@override
void handleEvent(PointerEvent event) {
if (!event.down && event.pointer == _p) {
_p = 0;
}
}
...
This completes our implementation of _SingleTouchRecognizer
class.
Now, just wrap the widget which needs multi-tap, multi-touch disabled by the custom widget you just created.
...
child: SingleTouchRecognizerWidget(
child: ListView.builder(
...
Reference: StackOverflow
Check out more useful articles on Flutter here.
You must be logged in to post a comment.