B4A Library [Lib] Gesture Detector

This library adds the detection of standard gestures (press, single-tap, double-tap, long tap, drag, scroll, fling, pinch, rotation) to B4A. Instead of using the Touch events to figure out what the user really did, now you just set 15 different listeners with one line of code and you get the gestures as events with all the useful values (scrolling distance, fling velocity, pinch variation, rotation angle...).
With this library, you can also know easily the pressure or the size of a touch event.

It works with any view.

Note: you have to create an instance of GestureDetector (with Dim) for each view you want to bind to the detector with SetOnGestureListener.

v2.2:
- Freeware.

v2.3:
- I fixed an issue with the boolean value returned by the OnTouch event with some views (e.g. ListView or ScrollView);
- I added a new demo (GD_SwipeLV);
- The OnDown event is now raised before OnDoubleTap.

v2.4:
- I fixed an issue when a view is dragged after one of the pointer is up (delta values were computed according to the pointer 0, not to the remaining pointer).

Incompatible with Android versions < 2.
 

Attachments

  • GestureDetector v2.4.zip
    35.3 KB · Views: 3,282
  • Java source - GestureDetector.zip
    5.5 KB · Views: 1,329
Last edited:

Informatix

Expert
Licensed User
Longtime User
Hi,

I'm afraid I also have another problem. I'm trying to handle the onFling Event, and sometimes before it gets to processing any of my code, it fails with the following error:
Fatal signal 11 (SIGSEGV) at 0x00000004 (code=1), thread 14134 (andrewj.stashit)

This is definitely in the fling handling, and happens even if I'm running release code. However if I comment out the whole onFling handler then I don't have any problem.

Any ideas?
Thanks
Andrew
I tried the GestureDetector_Drag demo in Debug(rapid) mode and had no issue with onFling (and never had an issue in the other modes) so it's a bit difficult to say what happens in your app without seeing the code of your event handler.
 
Last edited:

andrewj

Active Member
Licensed User
Longtime User
Thanks, that worked. It would be worth getting Erel to add it to the standard list. Unfortunately I've realised that it's not going to work for what I want to do, as I'm trying to send the event back to the same control which causes an endless loop! I've found another solution, but thanks anyway.
Andrew
 

siddsg

Member
Licensed User
Longtime User
This library adds the detection of standard gestures (press, single-tap, double-tap, long tap, drag, scroll, fling, pinch, rotation) to B4A. Instead of using the Touch events to figure out what the user really did, now you just set 15 different listeners with one line of code and you get the gestures as events with all the useful values (scrolling distance, fling velocity, pinch variation, rotation angle...).
With this library, you can also know easily the pressure or the size of a touch event.

It works with any view.

Note: you have to create an instance of GestureDetector (with Dim) for each view you want to bind to the detector with SetOnGestureListener.

v1.2: Freeware.
Support for multi-touch.
Incompatible with Android versions < 2.

v2.2: Donationware.
New events: onDrag, onPinchOpen, onPinchClose, onRotation
New functions: CreateMotionEvent, PassTouchEventTo, IgnoreWidthForPinch, IgnoreHeightForPinch, getHistorySize, getHistoricalX, getHistoricalY, getHistoricalPressure, getHistoricalSize, getTouchMajor, getTouchMinor, getXPrecision, getYPrecision, RemoveGestureListener.
Incompatible with Android versions < 2.

Starting from version 2, the GestureDetector library is released as a donationware. That means: if you want to use it in your application (or reuse a part of it in any piece of software written in B4A or Java), please donate something by using the link in my signature. I'll send you the file as soon as I receive your donation.

You can donate what you want, from one dollar to one million dollars (for such an amount, you'll be my friend forever ).
I don't do that to earn a lot of money, just to be rewarded for my work (and I probably won't earn a lot of money this way ;-)).
 

siddsg

Member
Licensed User
Longtime User
Hello Informatix,
I used your library, and its working fine as far as scrolling is concerned.
However, I want to stop the scrolling at a point.

Basically, I have a flashcards app where on scrolling from right to left, I fire a query to the db and retrieve a question and its answer.
So when I scroll once, it should retrieve Q1. On scrolling again, it should retrieve the corresponding answer.
However, when I scroll, it jut scrolls indefinitely and retrieves some random question/answer.

Could you please tell how to stop the scrolling?

Thank you,
Sidd
 

Informatix

Expert
Licensed User
Longtime User
Hello Informatix,
I used your library, and its working fine as far as scrolling is concerned.
However, I want to stop the scrolling at a point.

Basically, I have a flashcards app where on scrolling from right to left, I fire a query to the db and retrieve a question and its answer.
So when I scroll once, it should retrieve Q1. On scrolling again, it should retrieve the corresponding answer.
However, when I scroll, it jut scrolls indefinitely and retrieves some random question/answer.

Could you please tell how to stop the scrolling?

Thank you,
Sidd
Sorry, but I can't see why my library is involved in this problem. It's the view (and the corresponding library) that manages the scrolling that should be concerned. My library is mainly an event listener for touch actions; it has no code to start or stop a scrolling.
 

Joacim

Member
Licensed User
Longtime User
All of these events are of type boolean. When should I return true from the event?
 

Informatix

Expert
Licensed User
Longtime User
Thank you, but how do I do that: "Set the OnTouch listener to null"?
An example of the code I use is: GD.SetOnTouchListener(Button1, "GD_Button1")
Do you mean: GD.SetOnTouchListener(Button1, null) ??
Sorry, I thought you were talking of the Reflection library because, in my library, the function name is not SetOnTouchListener but SetOnGestureListener. To remove this listener, you have to call RemoveListener (in the donationware version) or use the Reflection lib (see this post).
10 gesture listeners are not a lot. It's even a very low number. You will probably start facing problems when you have hundreds of GD.
 

Informatix

Expert
Licensed User
Longtime User
Starting from September, the full version of the following classes and libraries will be available for free (but your donations will still be welcome):
- Gesture Detector
- File Explorer
- SlidingSidebar
I don't have enough time to continue to support them (and FileExplorer is completely outdated by the class provided with UltimateListView).
 

postasat

Active Member
Licensed User
Longtime User
I have a problem...
I read all the posts but I didn't find a full working solution.
I have a vertical scrollview and I want to do the following action:

If I swipe vertical, the event must be passed to scrollview, if I scroll horizontal (left to right) I will do an action (launching a sub), if I scroll horizontal (right to left) I must do a second action (launching another sub).

I tried using onFling event.
The horizontal swipe is working correctly, but if I have a vertical swipe and pass event to scrollview I have strange effects.
Using motionevent1 (null) give me errors, using motionevent2 (like in the code below) the scroll is slow and unpredictable.
I used reflector because with gesturedetector "passevent_to" I have an anomaly app stop error.

The code I use is the following:


B4X:
Sub Globals
Dim Gesture1 As GestureDetector

Sub Activity_Create
Gesture1.SetOnGestureListener(scvMain,"Gesture1")

Sub Gesture1_onFling(velocityX As Float, velocityY As Float, MotionEvent1 As Object, MotionEvent2 As Object)

'if horizontal speed is low, I'm scrolling vertical, I pass the event to scrollview (scvMain)
If Abs(velocityX) < positive_speed Then
    Dim r As Reflector
    r.Target = scvMain
    r.RunMethod4("onTouchEvent", Array As Object(MotionEvent2), Array As String("android.view.MotionEvent"))
Else
'if I have a vertical scroll from right to left
    If velocityX < negative_speed Then
            Button1_click
    Else    'from left to right
            Button2_click
    End If
End If
End Sub


Someone can help ?
Thank you !

Roberto.
 

Informatix

Expert
Licensed User
Longtime User
I have a problem...
I read all the posts but I didn't find a full working solution.
I have a vertical scrollview and I want to do the following action:

If I swipe vertical, the event must be passed to scrollview, if I scroll horizontal (left to right) I will do an action (launching a sub), if I scroll horizontal (right to left) I must do a second action (launching another sub).

I tried using onFling event.
The horizontal swipe is working correctly, but if I have a vertical swipe and pass event to scrollview I have strange effects.
Using motionevent1 (null) give me errors, using motionevent2 (like in the code below) the scroll is slow and unpredictable.
I used reflector because with gesturedetector "passevent_to" I have an anomaly app stop error.

The code I use is the following:


B4X:
Sub Globals
Dim Gesture1 As GestureDetector

Sub Activity_Create
Gesture1.SetOnGestureListener(scvMain,"Gesture1")

Sub Gesture1_onFling(velocityX As Float, velocityY As Float, MotionEvent1 As Object, MotionEvent2 As Object)

'if horizontal speed is low, I'm scrolling vertical, I pass the event to scrollview (scvMain)
If Abs(velocityX) < positive_speed Then
    Dim r As Reflector
    r.Target = scvMain
    r.RunMethod4("onTouchEvent", Array As Object(MotionEvent2), Array As String("android.view.MotionEvent"))
Else
'if I have a vertical scroll from right to left
    If velocityX < negative_speed Then
            Button1_click
    Else    'from left to right
            Button2_click
    End If
End If
End Sub


Someone can help ?
Thank you !

Roberto.
A ScrollView (or a ListView) intercepts touch events, so unless you block this interception with requestDisallowInterceptTouchEvent (search in the forum), you'll get unexpected results.

I used reflector because with gesturedetector "passevent_to" I have an anomaly app stop error.
You should try to understand why you get an error because that does not come from my code.
 

klaus

Expert
Licensed User
Longtime User
The code below works.
It uses the ScrollView Touch event added with the reflection library.
B4X:
Sub Globals
    Dim scvTest As ScrollView
    Dim x0, y0 As Float
    Dim swipe As Boolean
End Sub

Sub Activity_Create(FirstTime As Boolean)
    scvTest.Initialize(100)
    Activity.AddView(scvTest, 0, 0, 100%x, 100%y)
   
    Dim r As Reflector
    r.Target = scvTest
    r.SetOnTouchListener("scvTest_Touch")
   
    FillScrollView
End Sub

Sub scvTest_Touch(viewtag As Object, action As Int, X As Float, Y As Float, motionevent As Object) As Boolean
    Select action
    Case 0 ' DOWN
        x0 = X
        y0 = Y
    Case 2 ' MOVE
        If Abs(X - x0) > Abs(Y - y0) Then
            swipe = True
        Else
            swipe = False
        End If
    Case 1 ' UP
        If swipe = True Then
            If X - x0 > 40dip Then ' right swipe
                ToastMessageShow("Right swipe", False)
            Else If X - x0 < 40dip Then ' left swipe
                ToastMessageShow("Left swipe", False)
            End If
        End If
    End Select
    Return False
End Sub

Sub FillScrollView
    Dim i As Int
    Dim height = 50dip As Int
    Dim height_1 = height - 1dip As Int
   
    For i = 0 To 50
        Dim lbl As Label
        lbl.Initialize("")
        lbl.Text = "Test " & i
        scvTest.Panel.AddView(lbl, 0, i * height, 100%x, height_1)
    Next
    scvTest.Panel.Height = i * height
End Sub

Attached a small test program.
 

Attachments

  • ScrollViewHSwipe.zip
    6.4 KB · Views: 254

Informatix

Expert
Licensed User
Longtime User
The code below works.
It uses the ScrollView Touch event added with the reflection library.
B4X:
Sub Globals
    Dim scvTest As ScrollView
    Dim x0, y0 As Float
    Dim swipe As Boolean
End Sub

Sub Activity_Create(FirstTime As Boolean)
    scvTest.Initialize(100)
    Activity.AddView(scvTest, 0, 0, 100%x, 100%y)
  
    Dim r As Reflector
    r.Target = scvTest
    r.SetOnTouchListener("scvTest_Touch")
  
    FillScrollView
End Sub

Sub scvTest_Touch(viewtag As Object, action As Int, X As Float, Y As Float, motionevent As Object) As Boolean
    Select action
    Case 0 ' DOWN
        x0 = X
        y0 = Y
    Case 2 ' MOVE
        If Abs(X - x0) > Abs(Y - y0) Then
            swipe = True
        Else
            swipe = False
        End If
    Case 1 ' UP
        If swipe = True Then
            If X - x0 > 40dip Then ' right swipe
                ToastMessageShow("Right swipe", False)
            Else If X - x0 < 40dip Then ' left swipe
                ToastMessageShow("Left swipe", False)
            End If
        End If
    End Select
    Return False
End Sub

Sub FillScrollView
    Dim i As Int
    Dim height = 50dip As Int
    Dim height_1 = height - 1dip As Int
  
    For i = 0 To 50
        Dim lbl As Label
        lbl.Initialize("")
        lbl.Text = "Test " & i
        scvTest.Panel.AddView(lbl, 0, i * height, 100%x, height_1)
    Next
    scvTest.Panel.Height = i * height
End Sub

Attached a small test program.
Note that's easier to do with GestureDetector:
B4X:
Sub Globals
    Dim scvTest As ScrollView
    Dim GD As GestureDetector
End Sub

Sub Activity_Create(FirstTime As Boolean)
    scvTest.Initialize(100)
    GD.SetOnGestureListener(scvTest, "GD")
    Activity.AddView(scvTest, 0, 0, 100%x, 100%y)
    FillScrollView
End Sub

Sub GD_onScroll(distanceX As Float, distanceY As Float, MotionEvent1 As Object, MotionEvent2 As Object)
    If Abs(distanceX) > Abs(distanceY) Then
        Log("horizontal")
    Else
        Log("vertical")
    End If
End Sub
But it seems that postasat is trying to do something different as he wants to send touch events to the scrollview.
 

postasat

Active Member
Licensed User
Longtime User
Informatix, you're right.

The code above is perfect, but I need the correct code to pass event to scrollview only when Abs(distanceX) < Abs(distanceY).
So I need a code to place in place of "Log("vertical")" that send/pass motion event to scrollview.

Thank you.
 
Top