Android Tutorial Android multitouch tutorial

Using Agraham's Gestures library we can handle multitouch events.

This is an example of a simple drawing application that supports multitouch:

multitouch_1.png


As you can see in the above screenshot, each finger draws with a different color and it also displays the current id and position of each touch.

In order to support multitouch a Gestures object is used to add a listener to a specific view.
The listener is responsible for raising an event with every movement or change in the multitouch state.

Inside this event we are handling the gesture. Each touch gets a pointer id during a gesture. The pointer id is assigned when a finger touches the screen and is released when the same finger leaves the screen.

I find it useful to maintain a Map with the pointer ids as the keys and the the extra data that you want to assign to each touch as values.
In our example we store the color and the previous position as the value.

Maintaining the map is done with the following code:
B4X:
Sub GesturesTouch(View As Object, PointerID As Int, Action As Int, X As Float, Y As Float) As Boolean
    Dim p As Point
    Select Action
        Case g.ACTION_DOWN, g.ACTION_POINTER_DOWN
            'New Point is assigned to the new touch
            p.Id = PointerID
            p.Color = Colors.RGB(Rnd(0, 255), Rnd(0, 255), Rnd(0, 255))
            TouchMap.Put(PointerID, p)
        Case g.ACTION_POINTER_UP
            TouchMap.Remove(PointerId)
        Case g.ACTION_UP
            TouchMap.Clear
    End Select
  ...
The Point type is declared in Sub Globals:
B4X:
Type Point(Id As Int, prevX As Int, prevY As Int, Color As Int)
The result is that TouchMap holds information about the active touches.
Now all that is left to do is to iterate over the TouchMap values and connect the previous coordinates with the new ones and then update the previous coordinates.
The new coordinates are retrieved by calling g.GetX/Y with the pointer id.
B4X:
    Dim px, py As Int
    For i = 0 To TouchMap.Size - 1
        p = TouchMap.GetValueAt(i)
        px = g.GetX(p.id) 'Get the current coordinates of this touch
        py = g.GetY(p.id)
        Dim s As String
        s = p.Id & ": " & px & " x " & py
        Canvas.DrawText(s, 10dip, 20dip + i * RowHeight, Typeface.DEFAULT, TextSize, p.Color, "LEFT")
        If p.prevX > 0 AND p.prevY > 0 Then
            Canvas.DrawLine(p.prevX, p.prevY, px, py, p.Color, 5dip)
        End If
        p.prevX = px
        p.prevY = py
    Next
    bgd.Invalidate
p.prevX and p.prevY will equal 0 when the touch starts. In this case we do not draw anything.

The gesture sub should return true or otherwise no more events will be raised for this gesture.
 

Attachments

  • MultitouchExample.zip
    7.3 KB · Views: 1,050
Last edited:

hackhack

Active Member
Licensed User
Longtime User
So, were you going to do this anyway or is this your way of trying to get me to use the gesture library? ;)

Nice that its a small working demo (more comments), works on my phone and tablet - wee.
 

Nachtfalke75

Member
Licensed User
Longtime User
When i start the MultitouchExample on my emulator or on my lg p920 device i get the message "The application xxx has stopped unexpectedly" :(
 

Nachtfalke75

Member
Licensed User
Longtime User
Can you check the logs? There should be an error message with a stack trace.

Thanks for your fast answer. I used an old lib and installed the 1.2 one. now i get no error message, but the screen get black and nothing happens. at the emulator and the real device. When i compile it in debug modus, it works well. i dont understand that :(
Update:
Release works too
Release (obfuscated) don't work!
 
Last edited:

Nachtfalke75

Member
Licensed User
Longtime User
The problem is that GesturesTouch gets obfuscated and then the event cannot be raised.

Rename the event (and the SetListener line) to Gestures_Touch and it will work. The obfuscator doesn't obfuscate identifiers with underscore.
Ok, thank you :)
 

KiloOne

Member
Licensed User
Longtime User
After analyzing the multipoint data in vb6 I have noticed that when two fingers get close together, two distinct contact points merge into one.

The two fingers still have about 6 mm of 'non-contact on the touchscreen' between them.

This makes it very difficult to write a program that tracks 5 fingers.

This behavior can be observed with this tutorial code if you look closely.

Is there a way to prevent this 'finger merging' issue?

Thanks,
Dale
 

KiloOne

Member
Licensed User
Longtime User
Is there something like an operating system api that could be used to adjust the parameters involved in the blob merging issue?
 

Troberg

Well-Known Member
Licensed User
Longtime User
I keep getting events on a gesture even though I've returned False. In my case, I want to detect a two finger click as well as an ordinary one finger click.
B4X:
    If TouchMap.Size = 2 Then
        DoTwoFingerClick
        Return False
    Else If TouchMap.Size > 2 Then 'Not interested, end gesture
        Return False
    Else If TouchMap.Size = 0 AND Action = MultiTouch.ACTION_UP Then 'Size=0 because it has already been removed earlier in the code
        DoOneFingerClick
        Return False
    Else 'Wait for more
        Return True
    End If

What I would expect on a two finger click was this seqence:
ACTION_DOWN
ACTION_POINTER_DOWN
DoTwoFingerClick

However, what I get is:
ACTION_DOWN
ACTION_POINTER_DOWN
DoTwoFingerClick
ACTION_POINTER_UP
ACTION_UP
DoOneFingerClick

Not that hard to get around with a state variable, but still nice if it was fixed.
 

Informatix

Expert
Licensed User
Longtime User
I keep getting events on a gesture even though I've returned False. In my case, I want to detect a two finger click as well as an ordinary one finger click.
B4X:
    If TouchMap.Size = 2 Then
        DoTwoFingerClick
        Return False
    Else If TouchMap.Size > 2 Then 'Not interested, end gesture
        Return False
    Else If TouchMap.Size = 0 AND Action = MultiTouch.ACTION_UP Then 'Size=0 because it has already been removed earlier in the code
        DoOneFingerClick
        Return False
    Else 'Wait for more
        Return True
    End If

What I would expect on a two finger click was this seqence:
ACTION_DOWN
ACTION_POINTER_DOWN
DoTwoFingerClick

However, what I get is:
ACTION_DOWN
ACTION_POINTER_DOWN
DoTwoFingerClick
ACTION_POINTER_UP
ACTION_UP
DoOneFingerClick

Not that hard to get around with a state variable, but still nice if it was fixed.
You should look at the Gesture Detector lib.
 

Troberg

Well-Known Member
Licensed User
Longtime User
Returning false from this event doesn't end the gesture. It tells the system that the event was not consumed and it may be forward to a different view.

Ah, now I understand. The wording was a bit ambiguous. No problem, I just added a state variable, problem solved.
 

Troberg

Well-Known Member
Licensed User
Longtime User
You should look at the Gesture Detector lib.

I've missed that, but it wouldn't really help me in this instance. I cut down my example a bit, what I really do is to use two finger click with fingers side by side as toggle play/pause, and with fingers "over & under" to toggle mute.

I will probably use it in the future, though, for other uses.
 

Informatix

Expert
Licensed User
Longtime User
I've missed that, but it wouldn't really help me in this instance. I cut down my example a bit, what I really do is to use two finger click with fingers side by side as toggle play/pause, and with fingers "over & under" to toggle mute.

I will probably use it in the future, though, for other uses.
Yes, it would help because it ensures when you tap that the up event is in the same area than the down event (so it's really a click). That avoids issues when you click with two fingers on areas close to each other. But if that works fine with your current solution, so you don't really need it, of course.
 
Top