Add gesture controls in your app
Multi-finger touch refers to monitoring the touch events of multiple fingers. We can override the
onTouchEvent method in
Viewor use the
setOnTouchListener method to handle touch events.
First, let’s take a look at how to determine the event type of multi-finger touch.
Generally speaking, we judge the type of input event by judging the action of
MotionEventso as to make corresponding processing.
Without considering multiple fingers, we generally only focus on the following event types:
Tap the screen with the first finger
The last finger leaves the screen
A finger is swiping on the screen
So for multi-finger touch, in addition to the above-mentioned common event types, we also need to pay attention to two other event types:
A finger already exists on the screen before the tap
When one finger on the screen is lifted, there are still other fingers on the screen
It should be noted that the above two types cannot be obtained by using the
MotionEvent#getAction method as before, and need to use
So when dealing with multi-finger touch, our
onTouch method can generally be written like this:
When multiple fingers touch the screen at the same time, we need to track different fingers. There are several other concepts involved here.
There are several methods for tracking different fingers in
ActionIndex can be obtained directly through the
getActionIndex method, which can be roughly understood as describing the number of fingers that the current event occurs on. For example, when we monitor the finger lift, we may want to know which finger is lifted, then it can be judged by
In addition, for the same finger, the value of
ActionIndex may change as the finger is pressed and lifted, so we cannot use it to identify a finger.
It seems that the only purpose of
ActionIndex is to get the
In particular, it should be noted that this method is only valid for the
ACTION_POINTER_UP events. The
ACTION_MOVE event cannot accurately obtain the value. We need to make a comprehensive judgment in combination with other events.
PointerId is obtained through the
getPointerId(int) method, and the parameter is
We can identify a finger by
PointerId. For the same finger, the
PointerId is fixed throughout the process from pressing to lifting.
Also note that this value may be reused, for example, a finger with an
id of 0 may also have an
id of 0 when a finger is re-pressed after it has been lifted.
PointerIndex is obtained through
findPointerIndex(int)the parameter is
This value is used to get more content of the event.
If we want to get the click point position of the event, when we get the coordinates through the
getY() method, we can only get the position of the first finger, but these two methods provide an overload:
float getX(int pointerIndex);
float getY(int pointerIndex);
Through the above introduction, we have roughly understood some key points of multi-touch, and now let’s apply them in practice.
Here I will make a
DrawView for drawing finger movement trajectory, and it can track the trajectory of multiple fingers at the same time. The effect is as follows:
The picture above is the effect when swiping four fingers at the same time.
To achieve this effect, there are two main issues to consider:
The first is how to accurately track the sliding trajectory of a finger, because as mentioned above,
ACTION_MOVE cannot obtain
ActionIndex. But when God closes the door, he will definitely open a window. We can track it through
PointerId. First, listen to the two events of
PointerId of the new finger here, traverse all the fingers in the
ACTION_MOVE event, and then compare
PointerId can be either.
MotionEvent will package multiple consecutive sliding trajectories into one
MotionEventwe need to use
getHistoricalX to get the historical trajectory of this sliding. The method signature is as follows:
float getHistoricalX(int pointerIndex, int pos);
The first parameter,
pointerIndex, is easy to solve. The first question has already been mentioned, mainly the second parameter.
HistoricalX is a list, we need to read one by one through the index, and the second pos parameter is the index, but only if we know the length of the list. This can be solved with only one
MotionEvent provides a method to get the length of this list:
But this provides this method, there are no other overloads, so you can’t get the length of the history track list of a certain finger’s slide this time through
However, after my test, no matter which finger slides, you can get the length of the historical track through the
getHistorySize method, and then call the
getHistoricalX method to obtain the coordinates of the historical track.
Although I don’t know why it is designed this way, it does solve this problem.
We first define an inner class to act as drawing metadata:
DrawPath corresponds to the life cycle of a finger slide, that is, the trajectory experienced in the middle from DOWN to UP.
Then define a list of
DrawPath and variables such as brushes, track color arrays, etc.:
Now let’s override the
There are comments above, so I won’t go into detail.
Then rewrite the
onDraw method. Although this is a control for drawing tracks, there is not much code in the
In this way, a simple control that supports multi-finger drawing is realized, and we can also add some methods such as undoing the previous step to it. I won’t talk about it here.
The complete code for
DrawView has been put on GitHub.
You’re welcome to check it out.