UIGestureRecognizer Tutorial in Flutter: Taps, Drags, and More!

UIGestureRecognizer Tutorial in Flutter: Taps, Drags, and More!

Introduction

In this Flutter tutorial, you will learn how to add different types of gestures easily, also you will learn about drags to your app.

flutter1.22.3, Android studio 3.6.3

In Flutter, Gestures are primarily a way for the reader to interact with a mobile, using gestures like taps, pinches, pans, or rotations are used for the reader’s input. In your app, you can react to gestures, like a tap on text, without ever thinking about how to detect them. But in case you want to use gestures on views that don’t support them, you can easily do it with the built-in SDK

import package: flutter/gestures.dart libraries.

In this tutorial, you’ll learn how to add gesture recognizers to your app, programmatically using Dart language.

You’ll do this by creating an app where you can read online E-books using dragging, pinching, and rotating with the help of gesture recognizers.

You’ll also try out some cool extra features like:

  • Adding deceleration for movement
  • Drawing over certain parts of the screen
  • Creating a custom UIGestureRecognizer so you can select a particular area

This tutorial assumes you’re familiar with the basic concepts of Flutter and Dart. If you’re new to them, you may wish to check out our Flutter tutorials first.

It’s time to be a book geeks reader, so it’s time to get started!

Getting Started

Download and explore the starter project

Download the starter project using the?Materials?and open it up with your favorite IDE. This tutorial will be using Android Studio, but you can also use Visual Studio Code if that’s your preference. Make sure to run flutter packages get, either at the command line or when prompted by your IDE, to pull down the latest version of the HTTP package.

The starter project contains some basic models and networking files. When you open up the project it should look like this.

Gesture Detectors Overview

Before you get started, here’s a brief overview of why UIGestureDetectorss are so handy and how to use them.

Gestures are an interesting characteristic in Flutter that allows us to interact with the screen physically with different behaviors it can be single or multiple taps over the screen or maybe swiping in a different direction to perform a specific action, if you are trying to unlock your mobile phone with the pattern you will use gestures to draw your secret pattern also it’s heavily used in gaming to give you the ability to perform moves or using any gadgets in your game.

Gestures cycle

Gestures represent semantic actions like taps, drags, and scales that are recognized from pointer-events over the screen, so if you unlock your phone with the pattern, the cycle will be onPanStart() then when you start to move onPanUpdate() will be called, when you remove your hand the onPanEnd() will be called.

Create a gesture recognizer

When you create a gesture detector, you specify a target widget to be tapped and an action to be performed so the gesture detector widget can send you updates when the gesture starts, changes or ends.

Adding gestures to the views

You wrapped your target widget with a gesture detector widget. When a touch occurs within the bounds of that view, the gesture detector will check if it matches the type of touch it’s looking for. If it finds a match, it notifies the target.

You will perform these two steps later in this tutorial step by step, so Keep Going!

Implementing Tap Gestures

When you tap over the screen surface using your fingerprints The TapgesterRecognizer class is called to identify the Tap action type.

Using onTap() Gesture

The first implementation for Gestures will be onTap() To capture Tap actions over text widget so you will wrap the Padding widget with GestuerDetector() on bookTopic() widget then add the onTap() implementation inside.

onTap: () {
AlertViewDialogue().createAlertDialogue(context, false);
}

Now Build and run then tap over the text widget the alert dialogue should be viewed.

Great, you have implemented your first Tap Gesture, Now Let’s create more types of them.

Using onDoubleTap() Gesture

In GesterDetector() widget After onTap() you will add onDoubleTap() to allow the user to change the app to the dark mode, onDoubleTap() is similar to onTap() gesture, but it requires to tap twice over the widget to be triggered and execute its implementation.

onDoubleTap: () {
setState(() {
_changeColor = !_changeColor;
});
},

Now Build and run then tap twice over the text widget the app will change to the dark mode.

Using onLongPress() Gesture

So what if the reader has a LongPress() tap over text, so the alert dialogue should appear and view the source of our article and allow him to copy the link of our website, you should add.

onLongPress: () {
AlertViewDialogue().createAlertDialogue(context, true);
},

Now Build and run then tap and hold once over the text widget the alert dialogue should appear and contains the buttons to copy the meduim link.

Hooray, Now we have implemented several Tap detectors over the widget, Keep Going (Y)

Connecting Drag Gestures

You may notice that users need to change the topics in the E-book so in our design, we need users to change the page using dragging.

Dragging over widgets using pointers to describe the location and movement of the event in the screen surface

There are two types of dragging Vertical drag and Horizontal drag, each one of them has there lifecycle when the user starts, moves then removes its finger, you will implement both of them to let the user move forward and backward

When the pointer starts to contact the screen the lifecycle of drag will start then update then end providing us with Drag details that contain the velocity was moving along with the primary axis (X, Y)

Horizontal Dragging

When the reader will release his finger after dragging we need to check the values if it’s positive so that means we need to go to the next page if negative we need to back previous so add these lines in changePageview() after wrapping its container with GesterDetector widget.

GestureDetector(
onDoubleTap: () {
setState(() {
_changeColor = !_changeColor;
});
},
onHorizontalDragEnd: (DragEndDetails details) {
setState(() {
if (details.primaryVelocity > 1) {
_pageNumber <= 4 && _pageNumber != 0
? _pageNumber —
: _pageNumber = 4;
} else {
_pageNumber >= 0 && _pageNumber != 4
? _pageNumber++
: _pageNumber = 0;
}
});
},

Now Build and run you have to swipe right or left in the arrow’s area to change the page.

Vertical Dragging

If you need to do it with a vertical direction, You should add the same implementation but inside VerticalDragEnd()

onVerticalDragEnd: (DragEndDetails details) {
setState(() {
if (details.primaryVelocity > 1) {
_pageNumber <= 4 && _pageNumber != 0
? _pageNumber —
: _pageNumber = 4;
} else {
_pageNumber >= 0 && _pageNumber != 4
? _pageNumber++
: _pageNumber = 0;
}
});
},

Now Build and run you have to swipe up or down in the arrow’s area to change the page.

Good job till now let’s deep dive more!

Implementing Pan Gesture

What about if the reader wants to select or Mark a certain part of the text in the book, you should add this feature to your E-book as below.

To implement this we need to add PanGesture() means touching the surface of the screen with a fingertip, which can move in any direction without releasing the fingertip. This gesture contains events:

  • onPanStart
  • onPanUpdate
  • onPanEnd

Adding Pan Gesture To The widget

In The bookTopic() widget you will add the below code right after onLongPress()

onPanStart: (DragStartDetails details) {
_points.clear();
},
onPanUpdate: (DragUpdateDetails details) {
setState(() {
RenderBox object = context.findRenderObject();
Offset _localPosition = object.globalToLocal(details.localPosition);
_points = new List.from(_points)..add(_localPosition);
});
},
onPanEnd: (DragEndDetails details) => _points.add(null),

Screen Painting using onPanUpdate()

Inside setState() you will add RenderBox they size themselves based on those constraints and whatever other inputs they may have

The local position in the coordinate system of the event receiver at which the pointer contacted the screen

- Points mean the starting and the ending points you draw.

- Canvas current transformation matrix which applied all operations.

To paint over the screen your widget is wrapped with customPaint() to allow the user to draw over the screen and the ScreenDrawing class constructs an empty paint object while drawing and provides its attributes.

Now Build and run and try to mark any part of the text.

Using Scaling and Rotation Gestures

The Banner image maybe looks smaller, you need to add a zooming ability to the image also changing its orientation will be nice!

If you need to add this feature it requires a scaling widget that allows you to scale up or down easily.

Allow zooming Into the Widget

In the coverImageView() widget you need to wrap your container with GesterDetector() then add the following:

onScaleStart: (ScaleStartDetails details) {
_previousScale = _scale;
setState(() {});
},
onScaleUpdate: (ScaleUpdateDetails details) {
_scale = _previousScale * details.scale;
setState(() {});
},
onScaleEnd: (ScaleEndDetails details) {
_scale = 1.0;
setState(() {});
},

Using Rotation To Widget

For the Rotating image, you should wrap it with RotatedBox() widget and Transform() widget as well

Rotated Box: A widget that provides an easy way to rotate its child widget by the number of quarter turns

Transform: A widget that applies a transformation before painting its child using Matrices

Now Build and run and try to zoom using your fingers, also change image orientation while clicking over the app bar button.

Great, Let’s keep moving

Adding Reset Button

After readers draw over the screen they may need to remove the marked part, so you need to add a Reset button to remove points add over the screen.

Removing screen painting

You need to clear the screen using the points below.

setState(() {
_points.clear();
});

Now Build and run you should notice point removal

Handling multiple gestures

Sometimes you will need to add one or more gestures to the widget of the same types, but can you add onTap() twice in GesterDetector() widget?

The answer is no, the solution is to develop RawGestureDetector and a custom ‘GestureRecognizer’.

The custom GestureRecognizer provides Allow “MultipleGestureRecognizer” property to the gesture list and creates a

GestureRecognizerFactoryWithHandlers

Framework disambiguation

Using Multiple gestures listen to a stream of pointer events The GestureDetector widget decides which gestures to attempt to recognize based on which of its callbacks are non-null.

When there is more than one tap over the widget the framework disambiguates which gesture the user intends by having each recognizer join the gesture arena and determine which one will be executed.

Gesture arena

The gesture arena determines which gesture will be executed using the following rules:

  • At any time, a recognizer can declare defeat and leave the arena. If there’s only one recognizer left in the arena, that recognizer is the winner.
  • At any time, a recognizer can declare victory, which causes it to win and all the remaining recognizers to lose.

In your app, when disambiguating the onTap() detector, recognizers enter the arena when they receive the pointer down event. The recognizers observe the pointer move events.

Creating Custom Gesture

*You have three widgets to implement onTap() over them*

When the reader clicks over Copy Button it will copy the article URL if he clicked the visit site Button medium website link will be copied and the last part needs to be handled when he clicks in the empty space so the alert will disappear.

implement your own GestureDetector, using RawGestureDetector

CustomGestureRecognizer to the GestureRecognizerFactory in my RawGestureDetector to deal with the taps

Use instance to call the gesture type and add your logic inside

You will replace your container in the alert dialogue with the following implementation.

RawGestureDetector(
gestures: {
AllowMultipleGestureRecognizer:
GestureRecognizerFactoryWithHandlers<
AllowMultipleGestureRecognizer>(
() => AllowMultipleGestureRecognizer(), //constructor
(AllowMultipleGestureRecognizer instance) {
//initializer
instance.onTap = () {
print(“Row Tapped”);
Navigator.of(dialogContext).pop();
};
},
)
},
child: Container(
height: 50,
color: Colors.transparent,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
RawGestureDetector(
gestures: {
AllowMultipleGestureRecognizer:
GestureRecognizerFactoryWithHandlers<
AllowMultipleGestureRecognizer>(
() =>
AllowMultipleGestureRecognizer(), //constructor
(AllowMultipleGestureRecognizer instance) {
//initializer
instance.onTap = () {
Clipboard.setData(new ClipboardData(
text: Constants.rayUrl));
showToastMessage(context);
print(‘Copy Button Tapped’);
};
},
)
},
child: Container(
child: Center(
child: Text(
Constants.copyButton,
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.blue,
fontSize: 12),
),
)),
),
RawGestureDetector(
behavior: HitTestBehavior.deferToChild,
gestures: {
AllowMultipleGestureRecognizer:
GestureRecognizerFactoryWithHandlers<
AllowMultipleGestureRecognizer>(
() =>
AllowMultipleGestureRecognizer(), //constructor
(AllowMultipleGestureRecognizer instance) {
//initializer
instance.onTap = () {
Clipboard.setData(new ClipboardData(
text: Constants.mainUrl));
showToastMessage(context);
print(‘visit Site Tapped’);
};
},
)
},
child: Container(
height: 50,
child: Center(
child: Text(
Constants.visit,
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.blue,
fontSize: 12),
),
)),
),
],
),
),
),

Now Build and run the tap over text to view the alert dialogue and test your behavior!

Where to Go From Here?

Download the completed version of the project from the?Materials.

Congrats, you’re now a master of gesture detectors — both built-in and custom ones! Touch interaction is such an important part of flutter development and UIGestureDetector is the key to adding easy-to-use gestures beyond simple button taps.

There are many ways to add custom gestures and there is a challenge for you if you would link to make a more complex Custom Gesture you can mix two pan gestures together!

There is much more to learn and very useful resources to dig deep in you could check the official documentation.

https://docs.flutter.dev/development/ui/advanced/gestures

I hope you enjoyed this tutorial! If you have any questions or comments, please join the discussion below.

要查看或添加评论,请登录

社区洞察

其他会员也浏览了