請參閱Making Sense of Multitouch,它幫了我很多。它explanes如何處理多觸摸
要記住的要點
1.確保你打開action & MotionEvent.ACTION_MASK
2.如果你想畫在同一時間多行,請按照每個指針的PointerId其中進入MotionEvent.ACTION_POINTER_DOWN並通過比較指針ID來在MotionEvent.ACTION_POINTER_UP中釋放它。
private static final int INVALID_POINTER_ID = -1;
// The ‘active pointer’ is the one currently moving our object.
private int mActivePointerId = INVALID_POINTER_ID;
// Existing code ...
@Override
public boolean onTouchEvent(MotionEvent ev) {
final int action = ev.getAction();
switch (action & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN: {
final float x = ev.getX();
final float y = ev.getY();
mLastTouchX = x;
mLastTouchY = y;
// Save the ID of this pointer
mActivePointerId = ev.getPointerId(0);
break;
}
case MotionEvent.ACTION_MOVE: {
// Find the index of the active pointer and fetch its position
final int pointerIndex = ev.findPointerIndex(mActivePointerId);
final float x = ev.getX(pointerIndex);
final float y = ev.getY(pointerIndex);
final float dx = x - mLastTouchX;
final float dy = y - mLastTouchY;
mPosX += dx;
mPosY += dy;
mLastTouchX = x;
mLastTouchY = y;
invalidate();
break;
}
case MotionEvent.ACTION_UP: {
mActivePointerId = INVALID_POINTER_ID;
break;
}
case MotionEvent.ACTION_CANCEL: {
mActivePointerId = INVALID_POINTER_ID;
break;
}
case MotionEvent.ACTION_POINTER_UP: {
// Extract the index of the pointer that left the touch sensor
final int pointerIndex = (action & MotionEvent.ACTION_POINTER_INDEX_MASK)
>> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
final int pointerId = ev.getPointerId(pointerIndex);
if (pointerId == mActivePointerId) {
// This was our active pointer going up. Choose a new
// active pointer and adjust accordingly.
final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
mLastTouchX = ev.getX(newPointerIndex);
mLastTouchY = ev.getY(newPointerIndex);
mActivePointerId = ev.getPointerId(newPointerIndex);
}
break;
}
}
return true;
}
編輯
請參閱此代碼...這還是有一些問題,但我認爲你可以調試和修復這些......而且邏輯是不是有持續的線條,請執行該...
package com.example.stackgmfdght;
import java.util.ArrayList;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.util.Pair;
import android.view.MotionEvent;
import android.view.View;
public class JustDoIt extends View
{
private Canvas m_Canvas;
// private Path m_Path;
int current_path_count=-1;
ArrayList <Path> m_Path_list = new ArrayList<Path>();
ArrayList <Float> mX_list = new ArrayList<Float>();
ArrayList <Float> mY_list = new ArrayList<Float>();
ArrayList <Integer> mActivePointerId_list = new ArrayList<Integer>();
private Paint m_Paint;
ArrayList<Pair<Path, Paint>> arrayListPaths = new ArrayList<Pair<Path, Paint>>();
//ArrayList<Pair<Path, Paint>> undonePaths = new ArrayList<Pair<Path, Paint>>();
private float mX, mY;
private Bitmap bitmapToCanvas;
private static final float TOUCH_TOLERANCE = 4;
public JustDoIt (Context context)
{
super(context);
setFocusable(true);
setFocusableInTouchMode(true);
onCanvasInitialization();
}
public JustDoIt(Context context, AttributeSet attributeSet) {
super(context, attributeSet);
setFocusable(true);
setFocusableInTouchMode(true);
onCanvasInitialization();
}
public void onCanvasInitialization()
{
m_Paint = new Paint();
m_Paint.setAntiAlias(true);
m_Paint.setDither(true);
m_Paint.setColor(Color.parseColor("#37A1D1"));
m_Paint.setStyle(Paint.Style.STROKE);
m_Paint.setStrokeJoin(Paint.Join.ROUND);
m_Paint.setStrokeCap(Paint.Cap.ROUND);
m_Paint.setStrokeWidth(2);
// m_Path = new Path();
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh)
{
super.onSizeChanged(w, h, oldw, oldh);
bitmapToCanvas = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
m_Canvas = new Canvas(bitmapToCanvas);
}
@Override
protected void onDraw(Canvas canvas)
{
canvas.drawBitmap(bitmapToCanvas, 0f, 0f, null);
for(int i=0;i<=current_path_count;i++)
{
canvas.drawPath(m_Path_list.get(i), m_Paint);
}
}
public void onDrawCanvas()
{
for (Pair<Path, Paint> p : arrayListPaths)
{
m_Canvas.drawPath(p.first, p.second);
}
}
private static final int INVALID_POINTER_ID = -1;
// The ‘active pointer’ is the one currently moving our object.
private int mActivePointerId = INVALID_POINTER_ID;
@Override
public boolean onTouchEvent(MotionEvent event)
{
super.onTouchEvent(event);
final int action = event.getAction();
switch (action & MotionEvent.ACTION_MASK)
{
case MotionEvent.ACTION_DOWN:
{
float x = event.getX();
float y = event.getY();
current_path_count=0;
mActivePointerId_list.add (event.getPointerId(0),current_path_count);
touch_start((x),(y),current_path_count);
}
break;
case MotionEvent.ACTION_POINTER_DOWN:
{
if(event.getPointerCount()>current_path_count)
{
current_path_count++;
float x = event.getX(current_path_count);
float y = event.getY(current_path_count);
mActivePointerId_list.add (event.getPointerId(current_path_count),current_path_count);
touch_start((x),(y),current_path_count);
}
}
break;
case MotionEvent.ACTION_MOVE:
{
for(int i=0;i<=current_path_count;i++)
{ try{
int pointerIndex = event
.findPointerIndex(mActivePointerId_list.get(i));
float x = event.getX(pointerIndex);
float y = event.getY(pointerIndex);
touch_move((x),(y),i);
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
break;
case MotionEvent.ACTION_UP:
{ current_path_count=-1;
for(int i=0;i<=current_path_count;i++)
{
touch_up(i);
}
mActivePointerId_list = new ArrayList<Integer>();
}
break;
case MotionEvent.ACTION_CANCEL:
{
mActivePointerId = INVALID_POINTER_ID;
current_path_count=-1;
}
break;
case MotionEvent.ACTION_POINTER_UP:
{
final int pointerIndex = (event.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
final int pointerId = event.getPointerId(pointerIndex);
for(int i=0;i<=current_path_count;i++)
{
if (pointerId == mActivePointerId_list.get(i))
{
// This was our active pointer going up. Choose a new
// active pointer and adjust accordingly.
mActivePointerId_list.remove(i);
touch_up(i);
break;
}
}
}
break;
case MotionEvent.ACTION_OUTSIDE:
break;
}
invalidate();
return true;
}
private void touch_start(float x, float y, int count)
{
// undonePaths.clear();
Path m_Path=new Path();
m_Path_list.add(count,m_Path);
m_Path_list.get(count).reset();
m_Path_list.get(count).moveTo(x, y);
mX_list.add(count,x);
mY_list.add(count,y);
}
private void touch_move(float x, float y,int count)
{
float dx = Math.abs(x - mX_list.get(count));
float dy = Math.abs(y - mY_list.get(count));
if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE)
{
m_Path_list.get(count).quadTo(mX_list.get(count), mY_list.get(count), (x + mX_list.get(count))/2, (y + mY_list.get(count))/2);
try{
mX_list.remove(count);
mY_list.remove(count);
}
catch(Exception e)
{
e.printStackTrace();
}
mX_list.add(count,x);
mY_list.add(count,y);
}
}
private void touch_up(int count)
{
m_Path_list.get(count).lineTo(mX_list.get(count), mY_list.get(count));
// commit the path to our offscreen
m_Canvas.drawPath(m_Path_list.get(count), m_Paint);
// kill this so we don't double draw
Paint newPaint = new Paint(m_Paint); // Clones the mPaint object
arrayListPaths.add(new Pair<Path, Paint>(m_Path_list.get(count), newPaint));
m_Path_list.remove(count);
mX_list.remove(count);
mY_list.remove(count);
}
}
其實我通過這個文件,但在doc他們提到註冊多個觸摸我們需要MotionEvent.ACTION_POINTER_DOWN,但在他們的示例代碼,他們從未使用過,二來如果你不介意u能請幫我在我的代碼中實現它。其實我試過,但它不起作用。 – AndroidDev 2013-05-09 05:39:51
我在我的代碼中進行了更改作爲你的建議,但每當我用一根手指畫出時,它就會崩潰http://pastebin.com/uKwz24y5 – AndroidDev 2013-05-09 05:48:03
在你的代碼中ACTION_DOWN爲空,你可以從Action_down本身獲得指針ID,因爲ACTION_DOWN將成爲任何觸摸事件過程中的第一個事件,然後在每個其他手指的病房中調用ACTION_POINTER_DOWN。您需要獲取指針的計數,然後計算指針的索引並在ACTION_POINTER_DOWN和ACTION_POINTER_UP中管理它們。它可能需要一些時間才能完美實現.... – 2013-05-09 06:05:06