Android development blog
Tutorials about Android dev topics

Multi touch in Android : onTouchEvent example

In this post i want to analyse how Android handles the multitouch. Reading some posts around the net i found that are a bit confusing and not clear particularly when it comes the time to clarify how to detect how many fingers touching the screen.

To do it i will implement a custom View and i will guide you step by step. Let’s suppose you have already created an Android Project with an main Activity. The next step is create a class that extends android.view.View we call this class TouchView. Now we have our class and we need to create its constructor like that :
package it.jfrankie;


import android.content.Context;

import android.util.AttributeSet;

import android.util.Log;

import android.view.MotionEvent;

import android.view.View;


public class TouchView extends View {

 

 public TouchView(Context context) {

  super(context);  

 }


 public TouchView(Context context, AttributeSet attrs, int defStyle) {

  super(context, attrs, defStyle);  

 }


 public TouchView(Context context, AttributeSet attrs) {

  super(context, attrs);   

 }

}


Now we have our custom view that is very simple and don’t do nothing.

In the main.xml layout we have to declare it:
<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

    android:layout_width="fill_parent"

    android:layout_height="fill_parent"

    android:orientation="vertical" >


   <it.jfrankie.TouchView android:id="@+id/myView"

                           android:layout_width="fill_parent" 

                           android:layout_height="fill_parent"/>


</LinearLayout>

If we run our Android App we will have our empty custom view.

Now it is time go do a bit deeper and start handling the user’s touch on our view. To do it we have to override the method

@Override
    public boolean onTouchEvent(MotionEvent event) ;


and implement here the logic. The first thing we notice is we get as parameter a MotionEvent. This is the heart we will use such class to control the user fingers behaviour.

MotionEvent has a method that retrieves the action that is what the user is doing, this method is called getAction(). This returns an int value but we can’t use it directly because we need to mask it to retrieve the action performed by the user. Inside this value there are other thing we will check later. So to get the “real” action we have to do:

int action = event.getAction() & MotionEvent.ACTION_MASK;

MotionEvent.ACTION_MASK is the mask we apply against the getAction result. Now we know the real user action and we can check it against different predefined actions like:


Action Value

Action description
MotionEvent.ACTION_DOWNFirst finger is touching the screen. This is the primary finger
MotionEvent.ACTION_MOVEFinger is moving on the screen
MotionEvent.ACTION_POINTER_DOWNAnother finger is going down. This is not the primary finger
MotionEvent.ACTION_POINTER_UP Another finger is going up. This is not the primary finger
MotionEvent.ACTION_UP The primary finger is going up

So now, if we want to know the finger action, we have simply check all this conditions in this way:

@Override

 public boolean onTouchEvent(MotionEvent event) {

  int action = event.getAction() & MotionEvent.ACTION_MASK;

  switch(action) {

   case MotionEvent.ACTION_DOWN : {

    Log.d("CV","Pointer Down ");

    break;

   }

   case MotionEvent.ACTION_MOVE : {

    //Log.d("CV","Pointer Move ");

    break;

   }

   case MotionEvent.ACTION_POINTER_DOWN : {

    Log.d("CV", "Other point down");

    break;

   }

   case MotionEvent.ACTION_POINTER_UP : {

    Log.d("CV", "Other point up");

    break;

   }

   case MotionEvent.ACTION_UP : {

    Log.d("CV", "Pointer up");

    break;

   }   

  }

  return true;

 }

Remember to return true at the end of the method to inform the SO that we have handle correctly the event.

If you run your application and give a look at the log you will see all the events triggered when you touch the screen.

Now we know how to catch the user finger actions, we want to know more as for example how many fingers are touching the screen or their ids. We have to take into account that android handles two type of information: one is the finger index and the other is the finger id. What’s the difference? Well the index change during the time while the id remains the same for each finger. Once we know the index we can retrieve the id using the method getPointerId(int index). As said before the method getAction has several information: one of them is the index. We can retrieve this information masking it with MotionEvent.ACTION_POINTER_INDEX_MASK. Then to know the index we have to shift the value using MotionEvent.ACTION_POINTER_INDEX_SHIFT. So we can implement ts in a simple method:

private int getIndex(MotionEvent event) {

  int idx = (event.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;

  return idx;

Now we can rewrite our onTouch method to take into account the finger id:

@Override

 public boolean onTouchEvent(MotionEvent event) {

  int action = event.getAction() & MotionEvent.ACTION_MASK;

  

  switch(action) {

   case MotionEvent.ACTION_DOWN : {

    int id = event.getPointerId(0);

    Log.d("CV","Pointer Down ["+id+"]");

    break;

   }

   case MotionEvent.ACTION_MOVE : {

    break;

   }

   case MotionEvent.ACTION_POINTER_DOWN : {

    int id = event.getPointerId(getIndex(event));

    Log.d("CV", "Other point down ["+id+"]");

    break;

   }

   case MotionEvent.ACTION_POINTER_UP : {

    int id = event.getPointerId(getIndex(event));

    Log.d("CV", "Other point up ["+id+"]");

    

    break;

   }

   case MotionEvent.ACTION_UP : {

    int id = event.getPointerId(0);

    Log.d("CV", "Pointer up ["+id+"]");

    break;

   }   

  }

  return true;

 }


By now we didn’t take into account the MotionEvent.ACTION_MOVE. As the doc says this event is triggered whenever a change happens between MotionEvent.ACTION_DOWN and MotionEvent.ACTION_UP. So it is triggered for all the fingers touching the screen. The code below handles the move event:
 case MotionEvent.ACTION_MOVE : {

    int touchCounter = event.getPointerCount();

    for (int t = 0; t < touchCounter; t++) {

     int id = event.getPointerId(t);

     // Do something

    }

   }

You can download the source code here.




6 comments:

  1. Thank's for your interresting post,
    I understand better the multitouch in Android.

    However, I'v a little problem.
    How can I differentiate 2 fingers tap and three finger tap.
    Because if a tap my screen with three finger it trigger also top finger tap.

    Can you help me ?

    Thank you

    ReplyDelete
  2. You should use int id = event.getPointerId(t); each finger has its id.

    ReplyDelete
  3. I understand, but I've always the problème.

    If I do :


    case MotionEvent.ACTION_POINTER_DOWN :
    if(me.getPointerId() == 2){
    // Action for two finger
    }
    else if(me.getPointerId() == 3){
    // Action for the third finger
    }


    When I tap with three finger on the screen it trigger also the action associate with the second finger...

    ReplyDelete
  4. Nice post.Give it up. Thanks for share this article. For more visit:Web App Development

    ReplyDelete
  5. rajasimman rajasimmanSeptember 5, 2013 at 7:09 AM

    how to drag and drop multiple textview on single layout

    ReplyDelete
  6. how to rotate for custom textview in ontouch method
    if you know pls send me reply

    ReplyDelete

Related Posts with Thumbnails