Like it or not touch screens are becoming part of both developers and users life, i mean dont think i would buy one of Those uncool phones without touchscreen unless i really have to, would you? but the important point is that what is the Touchscreen use if applications doesn't support touchscreen interaction, in other words who is really gonna pay for a ,say, Picture management application if it does not support some gestures for switching between pictures or zooming? [ Gesture Detection in Android ].
In Android there are three levels of touch screen event handling mechanism which can be used by developers. the most low level technique is to receive all touch events and take care of all things, you can attach an 'OnTouchListener' to a view and get notified whenever there is a touch event or you can override onTouchEvent() or dispatchTouchEvent() method of your activity or view, in all these cases you would be dealing with an instance of MotionEvent every single time and you would have to detect what user is doing all on your own which will suit requirments for developing games and stuff like that. But it is just too much hassle if you only need a few simple gestures for your application.
Next approach is to use GestureDetector class along with OnGestureListener and/or OnDoubleTapListener, in this technique whenever there is a new MotionEvent you have to pass it to Gesture Detector's onTouchEvent() method, it then will analyse this event and previous events and tell you what is happening on the screen by calling some of the callback methods.
here is a simple activity which uses GestureDetector :
if we want to understand all gesture types and how they work, first of all we need to know three basic MotionEvents which can combine with each other and create some gestures, these three Events are Action_Down , Action_Move and Action_Up , each time you touch the screen an Action_Down occurs and when you start moving it will create Action_Move event and finally when you take your finger off the screen an Action_Up Event will be created.
onDown() is called simply when there is an Action_Down event.
onShowPress() is called after onDown() and before any other callback method, I found out it sometimes might not get called for example when you tap on the screen so fast, but it's actually what this method all about, to make a distinction between a possible unintentional touch and an intentional one.
onSingleTapUp() is called when there is a Tap Gesture. Tap Gesture happens when an Action_Down event followed by an Action_Up event(like a Single-Click).
onDoubleTap() is called when there is two consecutive Tap gesture(like a Double-Click).
onSingleTapConfirmed() is so similar to onSingleTapUp() but it is only get called when the detected tap gesture is definitely a single Tap and not part of a double tap gesture.
Here is the sequence in which these callback methods are called when we tap on the screen:
and here is when we do a double tap:
onFling() is called when a Fling Gesture is detected. fling Gesture occurs when there is an Action_Down then some Action_Move events and finally an Action_Up, but they must take place with a specified movement and velocity pattern to be considered as a fling gesture. for example if you put your finger on the screen and start moving it slowly and then remove your finger gently it won’t be count as a fling gesture.
onScroll() is usually called when there is a Action_Move event so if you put your finger on the screen and move it for a few seconds there will be a method call chain like this :
or If the movement was a Fling Gesture, then there would be a call chain like this :
If there is an Action_Move event between first tap and second tap of a doubleTap gesture it will be handled by calling onDoubleTapEvent() instead of onScroll() method. onDoubleTapEvent() receives all Action_Up events of a doubleTap gesture as well.
Remember that if we touch the screen and don’t remove our finger for a specified amount of time onLongPress() method is called and in most cases there will be no further event callback regardless of whatever we do after that, moving or removing our finger. we can easily change this behavior of detector by calling setIsLongpressEnabled() method of GestureDetector class.
although GestureDetector makes our life much easier, it still could be a real pain in the ass if we would need to handle some complicated gestures, imagine you need an application which should do task1 when there is a circle gesture, task2 for rectangle gesture and task3 for triangle gesture. obviously it would not be so pleasant to deal with such a situation with those mechanism we have seen so far, it's actually when Gesture API and Gesture Builder Application come into play.
Gesture Builder Application comes with Android emulator as a pre-installed app, It helps us to simply make new gestures and save them on the device, then we can retrieve and detect those gestures later using Gesture API. I'm not gonna talk about Gesture Builder app here,since there is a pretty good Article about it on Android Developers blog.
the only thing I'd like to mention here is GestureOverlayView class, It is actually just a transparent FrameLayout which can detect gestures but the thing is it can be used in two completely different ways, you can either put other views inside it and use it as a parent view or put it is the last child view of a FrameLayout (or any other way which causes it to be placed on top of another view).
In the first Scenario all child views will receive Touch events, therefore we will be able to press buttons or interact with other widgets as well as doing some gestures, on the other hand if GestureOverlayView has been placed on top, it will swallow all Touch events and no underlay view will be notified for any touch Event.
Although Gesture API brings many useful features for us, I personally prefer to use GestureDetector for some simple, basic gestures and honestly I feel like something is missing here, I mean , apart from games, I would say more than 70% of all gestures that might be needed in our applications are just a simple sliding in different directions or a double tap. and that's why I have decided to come up with something easy which can enable us to handle those 70% as simple as possible. how simple? you might be asking...
here is how our previous activity will look like if we use SimpleGestureFilter class :
and here is SimpleGestureFilter source code :
as you can see clients of these class can determine the minimum and maximum distance and also minimum velocity which is required for a movement on screen to be considered as a Swipe Gesture, I also thought it would be great if our filter can behave differently like what GestureOverlayView can do and even more than that!
this Filter can run in three different mode: Transparent, Solid and Dynamic. in Transparent mode it will work just like when we have a GestureOverlayView as parent: all views will receive Touch events; Solid mode works like when we put a GestureOverlayView as a child view: no one will receive TouchEvent, it is not as efficient as GestureOverlayView is, since we actually let all events get passed but what we do is we literally kill them when they are passing through our filter ;).
the last mode is Dynamic mode, the primary purpose of this mode is to have a bit smarter gesture detection, i mean there has been sometimes that i wanted to slide from one page to another, but a button get pressed and something else happens. it does not happen so much but it is really annoying. what i tried to do in Dynamic mode is to distinguish between a swipe/double tap gesture and a movement which is neither of them. so if you have a view full of buttons and other interactive stuff and user does a swipe or double tap gesture, it is guaranteed (although i believe there is no such thing as guarantee in life ;) ) that no other event callback will be called but only onSwipe() or onDoubleTap().
Anyway that's what i came up with to take the pain away in those circumstances when we just need to handle some simple Gestures.
hope it will be helpful for you and can make your life a bit easier.