May 24, 2011

Detect multi-touch, on SurfaceView

Override onTouchEvent() in SurfaceView to handle mlti-touch.



package com.TestSurefaceView;

import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

public class TestSurefaceView extends Activity {
 
 MySurfaceView mySurfaceView;
 
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mySurfaceView = new MySurfaceView(this);
        setContentView(mySurfaceView);
    }
    
    @Override
 protected void onResume() {
  // TODO Auto-generated method stub
  super.onResume();
  mySurfaceView.onResumeMySurfaceView();
 }

 @Override
 protected void onPause() {
  // TODO Auto-generated method stub
  super.onPause();
  mySurfaceView.onPauseMySurfaceView();
 }

 class MySurfaceView extends SurfaceView implements Runnable{
  
  //In this test, handle maximum of 2 pointer
  final int MAX_POINT_CNT = 2;
  
  private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
  float[] x = new float[MAX_POINT_CNT];
  float[] y = new float[MAX_POINT_CNT];
  boolean[] isTouch = new boolean[MAX_POINT_CNT];
  
  float[] x_last = new float[MAX_POINT_CNT];
  float[] y_last = new float[MAX_POINT_CNT];
  boolean[] isTouch_last = new boolean[MAX_POINT_CNT];

     
     Thread thread = null;
     SurfaceHolder surfaceHolder;
     volatile boolean running = false;
     
     volatile boolean touched = false;
     volatile float touched_x, touched_y;

  public MySurfaceView(Context context) {
   super(context);
   // TODO Auto-generated constructor stub
   surfaceHolder = getHolder();

  }
  
  public void onResumeMySurfaceView(){
   running = true;
   thread = new Thread(this);
   thread.start();
  }
  
  public void onPauseMySurfaceView(){
   boolean retry = true;
   running = false;
   while(retry){
    try {
     thread.join();
     retry = false;
    } catch (InterruptedException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
    }
   }
  }

  @Override
  public void run() {
   // TODO Auto-generated method stub
   while(running){
    if(surfaceHolder.getSurface().isValid()){
     Canvas canvas = surfaceHolder.lockCanvas();
     //... actual drawing on canvas

     paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeWidth(1);
     
     if(isTouch[0]){
      if(isTouch_last[0]){
       paint.setStyle(Paint.Style.STROKE);
          paint.setStrokeWidth(5);
          paint.setColor(Color.RED);
          canvas.drawLine(x_last[0], y_last[0], x[0], y[0], paint);
      }
     }
     if(isTouch[1]){
      if(isTouch_last[1]){
       paint.setStyle(Paint.Style.STROKE);
          paint.setStrokeWidth(5);
          paint.setColor(Color.BLUE);
          canvas.drawLine(x_last[1], y_last[1], x[1], y[1], paint);
      }
     }
     
     surfaceHolder.unlockCanvasAndPost(canvas);
    }
   }
  }

  @Override
  public boolean onTouchEvent(MotionEvent motionEvent) {
   int pointerIndex = ((motionEvent.getAction() & MotionEvent.ACTION_POINTER_ID_MASK) 
     >> MotionEvent.ACTION_POINTER_ID_SHIFT);
   int pointerId = motionEvent.getPointerId(pointerIndex);
   int action = (motionEvent.getAction() & MotionEvent.ACTION_MASK);
   int pointCnt = motionEvent.getPointerCount();
   
   if (pointCnt <= MAX_POINT_CNT){
    if (pointerIndex <= MAX_POINT_CNT - 1){

     for (int i = 0; i < pointCnt; i++) {
      int id = motionEvent.getPointerId(i);
      x_last[id] = x[id];
      y_last[id] = y[id];
      isTouch_last[id] = isTouch[id];
      x[id] = motionEvent.getX(i);
      y[id] = motionEvent.getY(i);
      }
     
     switch (action){
     case MotionEvent.ACTION_DOWN:
      isTouch[pointerId] = true;
      break;
     case MotionEvent.ACTION_POINTER_DOWN:
      isTouch[pointerId] = true;
      break;
     case MotionEvent.ACTION_MOVE:
      isTouch[pointerId] = true;
      break;
     case MotionEvent.ACTION_UP:
      isTouch[pointerId] = false;
      isTouch_last[pointerId] = false;
      break;
     case MotionEvent.ACTION_POINTER_UP:
      isTouch[pointerId] = false;
      isTouch_last[pointerId] = false;
      break;
     case MotionEvent.ACTION_CANCEL:
      isTouch[pointerId] = false;
      isTouch_last[pointerId] = false;
      break;
     default:
      isTouch[pointerId] = false;
      isTouch_last[pointerId] = false;
     }
    }
   }
   
   return true;
  }
     
    }
}


Related Post:
- Handle onTouchEvent in SurfaceView
- Draw path on SurfaceView's canvas

1 comment:

  1. thank you, great example. very easy to understand too :P

    ReplyDelete

Infolinks In Text Ads