07/08/2021 Multi-Touch & Gestures Detectors | Alexandria
MODULE
Multi-Touch & Gestures Detectors
Nawfal Ali
Updated 27 May 2020
Q) When does the multi-touch gesture happen?
A) It happens when more than one pointer ( nger) touches the screen.
Q) How to keep track of each pointer within a gesture? A) You have to use the pointer¡¯s index and ID.
Q) What is the purpose of having an Index and ID for each pointer?
A) Each pointer gets a unique ID during the gesture¡¯s lifetime and it is used to track the pointers within the gesture. This ID is generated once the pointer touches the screen and joins the gesture.
Now, the MotionEvent object saves all the pointers¡¯ data in a special array and uses indices to access the pointers¡¯ entries. These entries might shift up (change) if a pointer leaves the screen (the gesture) and this will lead to changes in pointers¡¯ indices.
Reference: https://developer.android.com/training/gestures/multi
Android system generates touch events every time multiple pointers touches the screen at the same time: (Click HERE for more details)
EVENT ACTION_DOWN
ACTION_POINTER_UP ACTION_POINTER_DOWN ACTION_MOVE ACTION_UP
DESCRIPTION
The first pointer (finger) touches the screen. The motion event object contains the initial st
A non-primary (secondary) pointer leaves the screen A non-primary (secondary) pointer touches the screen A motion happened to primary or non-primary pointer The last pointer leaves the screen
Android system provides several methods (MotionEvent methods) to deal with multi-touch events, such as:
METHOD DESCRIPTION
getPointerCount() The current number of pointers (fingers) on the screen
https://www.alexandriarepository.org/module/multi-touch-gestures-detectors/ 1/10
07/08/2021
Multi-Touch & Gestures Detectors | Alexandria
METHOD
getPointerId(int pointerIndex) findPointerIndex(int pointerId) getX(int pointerIndex) getY(int pointerIndex)
Gesture Detectors
DESCRIPTION
get the pointer id associated with a particular pointer data index in the current gesture find the pointer index for the given id
find the x coordinate for the given pointer index
find the y coordinate for the given pointer index
The gesture detector classes are used to detect common gestures through a set of motion events. There are three steps required for the gesture detector to work:
1. Create an instance of Gesture Detector class
2. Implements the required methods
3. Intercept the touch events and pass them to the gesture detector
Mainly, there are two classes of detectors GestureDetector and ScaleGestureDetector.
CLASS
INTERFACE
METHODS onDown(MotionEvent e)
onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY)
onLongPress(MotionEvent e)
onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY)
onShowPress(MotionEvent e) onSingleTapUp(MotionEvent e)
METHODS onDoubleTap(MotionEvent e)
onDoubleTapEvent(MotionEvent e) onSingleTapConfirmed(MotionEvent e)
DESCRIPTION
Notified when a tap occurs with the down MotionEvent th
Noti ed of a ing event when it occurs with e1 is the rst event (touch down)
e2 is the motion event that triggered the cur velocityX: The velocity of this event ( ing e velocityY: The velocity of this event ( ing e
Notified when a long press occurs with the initial on dow
Noti ed when a scroll occurs with the initia e1 is the rst event (touch down)
e2 is the current event
distanceX: the distance between e2 and the distanceX: the distance between e2 and the
The user has performed a down MotionEvent and not per Notified when a tap occurs with the up MotionEvent that
DESCRIPTION
Notified when a double-tap occurs.
Notified when an event within a double-tap gesture occur Notified when a single-tap occurs.
GestureDetector
OnGestureListener
CLASS
GestureDetector
INTERFACE
OnDoubleTapListener
https://www.alexandriarepository.org/module/multi-touch-gestures-detectors/ 2/10
v v
n
l
f t
s
07/08/2021 Multi-Touch & Gestures Detectors | Alexandria
CLASS INTERFACE METHOD
onScale(ScaleGestureDetector detector)
ScaleGestureDetector OnScaleGestureListener onScaleBegin(ScaleGestureDetector detector) onScaleEnd(ScaleGestureDetector detector)
Q) Some methods return boolean values, what does that mean?
A) If a callback method returns true, it informs the parent that the event has been consumed and ready to accept further events from the current gesture. But, if a callback returns false, it indicates that the event is not consumed and it is not interested in the remainder of the gesture.
Q) What are the di erences between onFling() and onScroll() callbacks?
A) 1) OnFling() needs some velocity in the movement (like swipe to unlock the phone). While, onScroll(), is invoked one you move your nger with normal speed (when you scroll a list or drag and drop)
2) onFlicg() will be called only once at the end of the gesture, while onScroll() will be called multiple times as you move your nger on the screen.
Instantiate a Gesture Detector instance
1. private GestureDetectorCompat mDetector;
2. private ScaleGestureDetector mScaleDetector;
3.
4. …
5. …
6. mDetector = new GestureDetectorCompat(this, this);
7. mScaleDetector = new ScaleGestureDetector(this, this);
Where the rst parameter is the context and the second one is a reference to the callbacks object.
Implements the required methods
It is possible to create a separate class to handle the implementation of all the callbacks or simply add them to the activity as shown below:
1. publicclassMainActivityextendsAppCompatActivityimplementsGestureDetector.OnGestureListener, GestureDetector.OnDoubleTapListener {
2.
3. }
https://www.alexandriarepository.org/module/multi-touch-gestures-detectors/ 3/10
07/08/2021 Multi-Touch & Gestures Detectors | Alexandria
https
4/10
1. @Override
2. public boolean onDown(MotionEvent e) {
3. return false;
4. }
5.
6. @Override
7. public void onShowPress(MotionEvent e) {
8.
9. }
10.
11. @Override
12. public boolean onSingleTapUp(MotionEvent e) {
13. return false;
14. }
15.
16. @Override
17. public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
18. return false;
19. }
20.
21. @Override
22. public void onLongPress(MotionEvent e) {
23. return false;
24.
25. }
26.
27. @Override
28. public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
29. return false;
30. }
31.
32. @Override
33. public boolean onSingleTapConfirmed(MotionEvent e) {
34. return false;
35. }
36.
37. @Override
38. public boolean onDoubleTap(MotionEvent e) {
39. return false;
40. }
41.
42. @Override
43. public boolean onDoubleTapEvent(MotionEvent e) {
44. return false;
45. }
46. 47.
48. @Override
49. public boolean onScale(ScaleGestureDetector detector) {
50. return false;
://www.alexandriarepository.org/module/multi-touch-gestures-detectors/
07/0
https
/2021 Multi-Touch & Gestures Detectors | Alexandria
5/10
Intercept the touch events and pass them to the gesture detector
For the gesture detectors to work, you must override the onTouch callback method and forward the MotionEvent object to the detectors.
Q) What will happen if your onTouch() callback returns false instead of true? Change it and observe the results.
1. 2. 3. 4. 5. 6. 7.
@Override
public boolean onTouch(View v, MotionEvent event) { mDetector.onTouchEvent(event)); mScaleDetector.onTouchEvent(event);
return true; }
Now, the activity in one piece:
51. } 52.
53. @Override
54. public boolean onScaleBegin(ScaleGestureDetector detector) {
55. return true;
56. }
57. @Override
58. public void onScaleEnd(ScaleGestureDetector detector) {
59.
60. }
1. packagecom.fit2081.week11gesturesdetectors; 2.
3. importandroidx.appcompat.app.AppCompatActivity;
4. importandroidx.core.view.GestureDetectorCompat;
5.
6. import android.os.Bundle;
7. importandroid.view.GestureDetector;
8. importandroid.view.MotionEvent;
9. import android.view.ScaleGestureDetector;
10. importandroid.view.View;
11. importandroid.widget.TextView;
12.
13. publicclassMainActivityextendsAppCompatActivityimplementsView.OnTouchListener,
GestureDetector.OnGestureListener, GestureDetector.OnDoubleTapListener, ScaleGestureDetector.OnScaleGestureListener { 14.
15. TextView tV;
16. private GestureDetectorCompat mDetector;
17. private ScaleGestureDetector mScaleDetector;
18.
://www.alexandriarepository.org/module/multi-touch-gestures-detectors/
8
07/0
https
/2021 Multi-Touch & Gestures Detectors | Alexandria
19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. 41. 42. 43. 44. 45. 46. 47. 48. 49. 50. 51. 52. 53. 54. 55. 56. 57. 58. 59. 60. 61. 62. 63. 64. 65. 66. 67. 68.
@Override
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main);
tV = findViewById(R.id.textview_id);
mScaleDetector = new ScaleGestureDetector(this, this);
mDetector = new GestureDetectorCompat(this, this); mDetector.setOnDoubleTapListener(this);
View myLayout = findViewById(R.id.myLayout); myLayout.setOnTouchListener(this);
}
@Override
public boolean onTouch(View v, MotionEvent event) { mDetector.onTouchEvent(event); mScaleDetector.onTouchEvent(event);
return true; }
@Override
public boolean onSingleTapConfirmed(MotionEvent e) { tV.setText(“onSingleTapConfirmed”);
return true;
}
@Override
public boolean onDoubleTap(MotionEvent e) { tV.setText(“onDoubleTap”);
return true;
}
@Override
public boolean onDoubleTapEvent(MotionEvent e) { tV.setText(“onDoubleTapEvent”);
return true; }
@Override
public boolean onDown(MotionEvent e) { tV.setText(“onDown”);
return true; }
://www.alexandriarepository.org/module/multi-touch-gestures-detectors/
8
6/10
07/0
https
/2021 Multi-Touch & Gestures Detectors | Alexandria
69. 70. 71. 72. 73. 74. 75. 76. 77. 78. 79. 80. 81. 82. 83. 84. 85. 86. 87. 88. 89. 90. 91. 92. 93. 94. 95. 96. 97. 98. 99. 100. 101. 102. 103. 104. 105. 106. 107. 108. 109. 110. 111. 112. 113. 114. 115. 116. 117. 118.
@Override
public void onShowPress(MotionEvent e) { tV.setText(“onShowPress”);
}
@Override
public boolean onSingleTapUp(MotionEvent e) { tV.setText(“onSingleTapUp”);
return true; }
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { tV.setText(“onScroll”);
return true; }
@Override
public void onLongPress(MotionEvent e) { tV.setText(“onLongPress”);
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { tV.setText(“onFling”);
return true; }
@Override
public boolean onScale(ScaleGestureDetector detector) { tV.setText(“onScale”);
return true; }
@Override
public boolean onScaleBegin(ScaleGestureDetector detector) { tV.setText(“onScaleBegin”);
return true; }
@Override
://www.alexandriarepository.org/module/multi-touch-gestures-detectors/
8
7/10
07/0
https
/2021 Multi-Touch & Gestures Detectors | Alexandria
8/10
Q) What will happen if onScaleBegin() callback returns false instead of true?
A) The two methods onScale() and onScaleEnd() will not be invoked.
Q) Why?
A) if the callback onScaleBegin() returns false, this means it is not interested in the current gesture.
Q) How can I get the pinch (zoom/scale) size at the end of the scale gesture?
A) you can return the event span using detector.getCurrentSpan() where detector is the input parameter to onScaleEnd() callback.
Click HERE for more information about the ScaleGestureDetector.
Q) What if want to implement only a subset of the callback? in other words, my app requires one or two callbacks only.
A) You need to implement a class that extends the convenience classes SimpleOnGestureListener or SimpleOnScaleGestureListener.
Build a class the extends SimpleOnGestureListener
119. 120. 121. 122. 123.
public void onScaleEnd(ScaleGestureDetector detector) { tV.setText(“onScaleEnd”);
} }
1. 2. 3. 4. 5. 6. 7. 8. 9.
10. 11. 12. 13. 14. 15. 16. 17. 18.
privateclassMyGestureListenerextendsGestureDetector.SimpleOnGestureListener{
@Override
public boolean onSingleTapConfirmed(MotionEvent e) { tV.setText(“onSingleTapConfirmed”);
return true;
}
@Override
public boolean onDoubleTap(MotionEvent e) { tV.setText(“onDoubleTap”);
return true;
}
@Override
public boolean onDown(MotionEvent e) { tV.setText(“onDown”);
://www.alexandriarepository.org/module/multi-touch-gestures-detectors/
8
07/0
https://www.alexandriarepository.org/module/multi-touch-gestures-detectors/ 9/10
/2021 Multi-Touch & Gestures Detectors | Alexandria
As you can see from the code above, the class MyGestureListener which works as a listener implements a subset of the interface OnGestureListener callbacks.
Build a class the extends SimpleOnScaleGestureListener
1. 2. 3. 4. 5. 6. 7. 8. 9.
10. 11. 12. 13. 14. 15. 16.
privateclassMyScaleListenerextendsScaleGestureDetector.SimpleOnScaleGestureListener{ @Override
public boolean onScale(ScaleGestureDetector detector) { tV.setText(“onScale”);
return true; }
@Override
public boolean onScaleBegin(ScaleGestureDetector detector) { tV.setText(“onScaleBegin”);
return true; }
}
Again, extending the convenience class SimpleOnScaleGestureListener allows you to implement only the callbacks which your application needs.
Now, let¡¯s provide them to the detectors:
19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34.
return true; }
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { tV.setText(“onScroll”);
return true; }
@Override
public void onLongPress(MotionEvent e) { tV.setText(“onLongPress”);
} }
1. MyScaleListener MyScaleListener=new MyScaleListener();
2. mScaleDetector = new ScaleGestureDetector(this, MyScaleListener);
3.
4. MyGestureListener myGestureListener = new MyGestureListener();
5. mDetector = new GestureDetectorCompat(this, myGestureListener);
6. mDetector.setOnDoubleTapListener(myGestureListener);
8
07/08/2021 Multi-Touch & Gestures Detectors | Alexandria
Copyright ý Monash University, unless otherwise stated. All Rights Reserved, except for individual components (or items) marked with their own licence restrictions
Copyright ý 2021 Monash University, unless otherwise stated
Disclaimer and Copyright Privacy
Service Status
https://www.alexandriarepository.org/module/multi-touch-gestures-detectors/ 10/10