How to React to Touch Events in Flutter

Almost every app will need some sort of user input. Usually your app will need to respond to touch events.This is a small guide to touch events, especially for starting Flutter developers.

When it comes to gesture recognition and reaction to touch events, Flutter offers incredible widgets for new developers. You can make any widget in your app respond to touch events by just wrapping it in one of these touch recognition widgets.

Whether you are a developer just learning more about the management of touch events on Flutter, or a professional looking for a quick recap, this post will get you up to speed.

How Does the Gesture System Operates?

Essentially, the gesture system in Flutter operates on two distinct layers. The first layer stores the raw pointer events that describe the physical details like location and movement of the pointers in use like the styli, mice, and touches in general.

Above this, we have the layer of ‘gestures’. This interprets the pointer movements as meaningful semantics and adds a context to the pointer movements.

A Quick Touch Events Glossary for Beginners

Touch events cannot be handled unless you understand semantic gestures and pointers. The pointer is the hero in this arena! You’ll see how this is literally true below.

Before we explore the reaction of individual elements, let’s have a look at the features involved in the case:

Pointers

Pointers represent raw data related to user interaction with the screen in question. There are four different types of pointer events:

PointerUpEvent: The pointer has stopped interacting with the screen.

PointerDownEvent: The pointer is in contact with the screen at a specific location.

PointerMoveEvent: The pointer has moved to a new position on the screen.

PointerCancelEvent: The input of this pointer is no longer directed towards the app in progress.

When you engage the PointerDownEvent, the framework will examine the app to determine the widget located on that specific point on the app’s wireframe. The PointerDownEvent will be dispatched to that widget and the widgets above it to the root of the component tree, and so too will any events that follow the down event on that particular path.

Gestures

As mentioned earlier, gestures represent the semantic actions such as tap, scale and drag that are easily recognized from multiple individual events emerging from a pointer activity. A single gesture could possibly incorporate multiple touch events, each handling a unique milestone of the gesture like the drag start or drag end!

Here are the most common types of gestures involved in Touch Event Management on Flutter:

Tap Gestures

onTapUp: A pointer triggers a tap on a particular location on screen.

onTapDown: A pointer might cause a tap has been contacted on screen.

onTap: When pointer previously triggered onTapDown also triggers onTapUp, causing a tap.

onTapCancel: When the pointer triggering onTapDown will not cause a tap.

Double Tap Gestures

onDoubleTap: The user taps the screen at the same position twice in quick succession.

Long Press Gestures

onLongPress: A pointer remains in contact with the screen on the same location for a longer chunk of time.

Vertical Drag Gestures

onVerticalDragStart: The pointer contact screen to probably move vertically.

onVerticalDragEndA pointer that had previously been in contact with the screen during a vertical movement ends contact with the screen on a similar velocity as the movement itself.

onVerticalDragUpdate: A pointer that is in contact with the screen moves vertically in the same direction.

Horizontal Drag Gestures

onHorizontalDragStart: A pointer contacts the screen to potentially move in the horizontal direction.

onHorizontalDragEnd: A pointer that was previously moving horizontally with contact to the screen, with a specific velocity, loses contact altogether.

onHorizontalDragUpdate: A pointer in contact with the screen moves horizontally from the onHorizontalDragStart.

Pan Gestures

onPanStart: a pointer has contacted the screen and can potentially move on the X or Y axis. This callback leads to a crash when onHorizontalDragStart or onVerticalDragStart have been set—there is no way for the event system to disambiguate between a pan or a drag.

onPanEnd: a pointer that had been in contact with the screen and was previously moving at a specific velocity loses contact with the screen. A crash is caused when the callback is set at onHorizontalDragEnd or onVerticalDragEnd.

onPanUpdate: A pointer that is currently is contact with the screen and moving in either horizontal or vertical direction. Crashes are only experienced when the callback for onHorizontalDragUpdate or onVerticalDragUpdate is set.

Understanding Gesture Disambiguation

Multiple gesture detectors can be present on any given location on the screen. All of them follow the cues from the stream of pointer events that flow past. In an attempt to recognize specific gestures, the GestureDetector widget determines specified semantic gestures according to which callbacks have been set. Meaning, if you set a certain callback on the GestureDetector, the widget will try to interpret the pointer events in terms of that type of gesture.

The framework disambiguates gestures in the gesture arena. Each type of gesture has a recognizer which competes in the arena, examining the pointer position and movements events that come in. The recognizer which corresponds to the input gesture wins by following a few rules:

A recognizer is free to declare defeat at any time and leave the arena. When only one recognizer is left, then it wins!
A recognizer can declare victory at any time and force others to claim defeat.

For example, suppose you want to recognize vertical and horizontal drags. Recognizers for each direct will enter the gesture arena as soon as they receive the first event event. They will then observe the movement in terms of logical pixels in any given direction.

If the move event proceeds mostly vertically, the vertical recognizer will declare victory due to the logical pixels crossed and hence the gesture will be interpreted as a vertical drag on the screen. The same series of events can be repeated for horizontal drags too.

If you only want to recognize horizontal drags, then it doesn’t matter whether there is a vertical component to the movement, only the horizontal movement will be recognized.

Coding Touch Event Processing In Flutter

When working in Android, you can respond to buttons taps by binding OnClick through the setOnClickListener. But when it comes to Flutter, you have the choice of two different methods of adding a touch listener.

If the widget supports the use of listeners then you can pass a callback function to process the event. Here is a sample of code for onPressed and RaisedButton parameter:

class BodyWidget extends StatelessWidget {

@override
Widget build(BuildContext context) {

return RaisedButton(
onPressed: (){
print(“Click!”);
},

child: Align(
alignment: Alignment.center,
child: new Text(“Button”, softWrap: true)
),
);

}
}

And this is how it would look in your app.

GestureDetector Example

However, you’ll often want to use a listener that is not already supported by the widget. When a listener is not directly supported by the widget, you can wrap that widget in GestureDetector and pass the handler to the onTap parameter instead. Here’s how:

class SampleApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: ‘Flutter App’,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Flutter_App(),
);
}
}

class Flutter_App extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return _State();
}
}

class _State extends State<Flutter_App>
with SingleTickerProviderStateMixin {

@override
Widget build(BuildContext context) {
return MaterialApp(
title: ‘Flutter App’,
theme: ThemeData(primaryColor: Colors.blue),
home: Scaffold(
appBar: AppBar(
title: Text(‘Flutter App’),
),
body: Center(
child: GestureDetector(
child: FlutterLogo(
size: 200.0,
),

onTap: () {
print(“Tap”);
},
),
)));
}

@override
void dispose() {
// Resource release
super.dispose();
}
}

And this what the app will look like:

Animate on Double Tap Example

Here is another prime example of a touch event reaction for a double tap on the Flutter logo that causes a visual rotation.

Wondering how to listen for the double tap event? This is how:

class SampleApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: ‘Sample App’,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: AnimateApp(),
);
}
}

class AnimateApp extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return _AnimateAppState();
}
}

class _AnimateAppState extends State<AnimateApp>
with SingleTickerProviderStateMixin {
AnimationController controller;
Animation<double> animation;
CurvedAnimation curve;

@override
void initState() {
super.initState();
// Create AnimationController object
controller = AnimationController(
vsync: this, duration: const Duration(milliseconds: 2000));
curve = CurvedAnimation(parent: controller, curve: Curves.easeIn);
// Create Animation object through Tween object
animation = Tween(begin: 50.0, end: 200.0).animate(controller)
..addListener(() {
// Note: This sentence cannot be omitted, otherwise the widget will not be redrawn and the animation effect will not be seen
setState(() {});
});
// Perform animation
controller.forward();
}

@override
Widget build(BuildContext context) {
return MaterialApp(
title: ‘AnimateApp’,
theme: ThemeData(primaryColor: Colors.blue),
home: Scaffold(
appBar: AppBar(
title: Text(‘AnimateApp’),
),
body: Center(
child: GestureDetector(
child: RotationTransition(
turns: curve,
child: FlutterLogo(
size: 200.0,
)),
onDoubleTap: () {
if (controller.isCompleted) {
controller.reverse();
} else {
controller.forward();
}
},
),
)));
}

@override
void dispose() {
// Resource release
controller.dispose();
super.dispose();
}
}

Final Thoughts

Reacting to touch events on Flutter is not as complicated as one would assume. Understanding the nature of widgets and their ability to listen is the first lesson you need. And all else follows smoothly from there.

Generated by Feedzy