Android开发:多点触控测试精华代码

PointerLocationView.java:

/*
 * Copyright (C) 2010 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.ckl.PointerLocation;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Paint.FontMetricsInt;
import android.util.Log;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;

import java.util.ArrayList;

public class PointerLocationView extends View {
	public static class PointerState {
		private final ArrayList mXs = new ArrayList();
		private final ArrayList mYs = new ArrayList();
		private boolean mCurDown;
		private int mCurX;
		private int mCurY;
		private float mCurPressure;
		private float mCurSize;
		private int mCurWidth;
		private VelocityTracker mVelocity;
	}

	private final ViewConfiguration mVC;
	private final Paint mTextPaint;
	private final Paint mTextBackgroundPaint;
	private final Paint mTextLevelPaint;
	private final Paint mPaint;
	private final Paint mTargetPaint;
	private final Paint mPathPaint;
	private final FontMetricsInt mTextMetrics = new FontMetricsInt();
	private int mHeaderBottom;
	private boolean mCurDown;
	private int mCurNumPointers;
	private int mMaxNumPointers;
	private final ArrayList mPointers = new ArrayList();

	private boolean mPrintCoords = true;

	public PointerLocationView(Context c) {
		super(c);
		setFocusable(true);
		mVC = ViewConfiguration.get(c);
		mTextPaint = new Paint();
		mTextPaint.setAntiAlias(true);
		mTextPaint.setTextSize(10 * getResources().getDisplayMetrics().density);
		mTextPaint.setARGB(255, 0, 0, 0);
		mTextBackgroundPaint = new Paint();
		mTextBackgroundPaint.setAntiAlias(false);
		mTextBackgroundPaint.setARGB(128, 255, 255, 255);
		mTextLevelPaint = new Paint();
		mTextLevelPaint.setAntiAlias(false);
		mTextLevelPaint.setARGB(192, 255, 0, 0);
		mPaint = new Paint();
		mPaint.setAntiAlias(true);
		mPaint.setARGB(255, 255, 255, 255);
		mPaint.setStyle(Paint.Style.STROKE);
		mPaint.setStrokeWidth(2);
		mTargetPaint = new Paint();
		mTargetPaint.setAntiAlias(false);
		mTargetPaint.setARGB(255, 0, 0, 192);
		mPathPaint = new Paint();
		mPathPaint.setAntiAlias(false);
		mPathPaint.setARGB(255, 0, 96, 255);
		mPaint.setStyle(Paint.Style.STROKE);
		mPaint.setStrokeWidth(1);

		PointerState ps = new PointerState();
		ps.mVelocity = VelocityTracker.obtain();
		mPointers.add(ps);
	}

	public void setPrintCoords(boolean state) {
		mPrintCoords = state;
	}

	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
		mTextPaint.getFontMetricsInt(mTextMetrics);
		mHeaderBottom = -mTextMetrics.ascent + mTextMetrics.descent + 2;
		if (false) {
			Log.i("foo", "Metrics: ascent=" + mTextMetrics.ascent + " descent="
					+ mTextMetrics.descent + " leading=" + mTextMetrics.leading
					+ " top=" + mTextMetrics.top + " bottom="
					+ mTextMetrics.bottom);
		}
	}

	@Override
	protected void onDraw(Canvas canvas) {
		synchronized (mPointers) {
			final int w = getWidth();
			final int itemW = w / 7;
			final int base = -mTextMetrics.ascent + 1;
			final int bottom = mHeaderBottom;
			final int NP = mPointers.size();

			if (NP > 0) {
				final PointerState ps = mPointers.get(0);
				canvas.drawRect(0, 0, itemW - 1, bottom, mTextBackgroundPaint);
				canvas.drawText("P: " + mCurNumPointers + " / "
						+ mMaxNumPointers, 1, base, mTextPaint);

				final int N = ps.mXs.size();
				if ((mCurDown && ps.mCurDown) || N == 0) {
					canvas.drawRect(itemW, 0, (itemW * 2) - 1, bottom,
							mTextBackgroundPaint);
					canvas.drawText("X: " + ps.mCurX, 1 + itemW, base,
							mTextPaint);
					canvas.drawRect(itemW * 2, 0, (itemW * 3) - 1, bottom,
							mTextBackgroundPaint);
					canvas.drawText("Y: " + ps.mCurY, 1 + itemW * 2, base,
							mTextPaint);
				} else {
					float dx = ps.mXs.get(N - 1) - ps.mXs.get(0);
					float dy = ps.mYs.get(N - 1) - ps.mYs.get(0);
					canvas.drawRect(
							itemW,
							0,
							(itemW * 2) - 1,
							bottom,
							Math.abs(dx) < mVC.getScaledTouchSlop() ? mTextBackgroundPaint
									: mTextLevelPaint);
					canvas.drawText("dX: " + String.format("%.1f", dx),
							1 + itemW, base, mTextPaint);
					canvas.drawRect(
							itemW * 2,
							0,
							(itemW * 3) - 1,
							bottom,
							Math.abs(dy) < mVC.getScaledTouchSlop() ? mTextBackgroundPaint
									: mTextLevelPaint);
					canvas.drawText("dY: " + String.format("%.1f", dy),
							1 + itemW * 2, base, mTextPaint);
				}

				canvas.drawRect(itemW * 3, 0, (itemW * 4) - 1, bottom,
						mTextBackgroundPaint);
				int velocity = ps.mVelocity == null ? 0 : (int) (ps.mVelocity
						.getXVelocity() * 1000);
				canvas.drawText("Xv: " + velocity, 1 + itemW * 3, base,
						mTextPaint);

				canvas.drawRect(itemW * 4, 0, (itemW * 5) - 1, bottom,
						mTextBackgroundPaint);
				velocity = ps.mVelocity == null ? 0 : (int) (ps.mVelocity
						.getYVelocity() * 1000);
				canvas.drawText("Yv: " + velocity, 1 + itemW * 4, base,
						mTextPaint);

				canvas.drawRect(itemW * 5, 0, (itemW * 6) - 1, bottom,
						mTextBackgroundPaint);
				canvas.drawRect(itemW * 5, 0, (itemW * 5)
						+ (ps.mCurPressure * itemW) - 1, bottom,
						mTextLevelPaint);
				canvas.drawText(
						"Prs: " + String.format("%.2f", ps.mCurPressure),
						1 + itemW * 5, base, mTextPaint);

				canvas.drawRect(itemW * 6, 0, w, bottom, mTextBackgroundPaint);
				canvas.drawRect(itemW * 6, 0, (itemW * 6)
						+ (ps.mCurSize * itemW) - 1, bottom, mTextLevelPaint);
				canvas.drawText("Size: " + String.format("%.2f", ps.mCurSize),
						1 + itemW * 6, base, mTextPaint);
			}

			for (int p = 0; p < NP; p++) {
				final PointerState ps = mPointers.get(p);

				if (mCurDown && ps.mCurDown) {
					canvas.drawLine(0, (int) ps.mCurY, getWidth(),
							(int) ps.mCurY, mTargetPaint);
					canvas.drawLine((int) ps.mCurX, 0, (int) ps.mCurX,
							getHeight(), mTargetPaint);
					int pressureLevel = (int) (ps.mCurPressure * 255);
					mPaint.setARGB(255, pressureLevel, 128, 255 - pressureLevel);
					canvas.drawPoint(ps.mCurX, ps.mCurY, mPaint);
					canvas.drawCircle(ps.mCurX, ps.mCurY, ps.mCurWidth, mPaint);
				}
			}

			for (int p = 0; p < NP; p++) {
				final PointerState ps = mPointers.get(p);

				final int N = ps.mXs.size();
				float lastX = 0, lastY = 0;
				boolean haveLast = false;
				boolean drawn = false;
				mPaint.setARGB(255, 128, 255, 255);
				for (int i = 0; i < N; i++) {
					float x = ps.mXs.get(i);
					float y = ps.mYs.get(i);
					if (Float.isNaN(x)) {
						haveLast = false;
						continue;
					}
					if (haveLast) {
						canvas.drawLine(lastX, lastY, x, y, mPathPaint);
						canvas.drawPoint(lastX, lastY, mPaint);
						drawn = true;
					}
					lastX = x;
					lastY = y;
					haveLast = true;
				}

				if (drawn) {
					if (ps.mVelocity != null) {
						mPaint.setARGB(255, 255, 64, 128);
						float xVel = ps.mVelocity.getXVelocity() * (1000 / 60);
						float yVel = ps.mVelocity.getYVelocity() * (1000 / 60);
						canvas.drawLine(lastX, lastY, lastX + xVel, lastY
								+ yVel, mPaint);
					} else {
						canvas.drawPoint(lastX, lastY, mPaint);
					}
				}
			}
		}
	}

	public void addTouchEvent(MotionEvent event) {
		synchronized (mPointers) {
			int action = event.getAction();

			// Log.i("Pointer", "Motion: action=0x" +
			// Integer.toHexString(action)
			// + " pointers=" + event.getPointerCount());

			int NP = mPointers.size();

			// mRect.set(0, 0, getWidth(), mHeaderBottom+1);
			// invalidate(mRect);
			// if (mCurDown) {
			// mRect.set(mCurX-mCurWidth-3, mCurY-mCurWidth-3,
			// mCurX+mCurWidth+3, mCurY+mCurWidth+3);
			// } else {
			// mRect.setEmpty();
			// }
			if (action == MotionEvent.ACTION_DOWN) {
				for (int p = 0; p < NP; p++) {
					final PointerState ps = mPointers.get(p);
					ps.mXs.clear();
					ps.mYs.clear();
					ps.mVelocity = VelocityTracker.obtain();
					ps.mCurDown = false;
				}
				mPointers.get(0).mCurDown = true;
				mMaxNumPointers = 0;
				if (mPrintCoords) {
					Log.i("Pointer", "Pointer 1: DOWN");
				}
			}

			if ((action & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_POINTER_DOWN) {
				final int index = (action & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
				final int id = event.getPointerId(index); // 对于每个触控的点的细节,我们可以通过一个循环执行getPointerId方法获取索引

				while (NP <= id) {
					PointerState ps = new PointerState();
					ps.mVelocity = VelocityTracker.obtain();
					mPointers.add(ps);
					NP++;
				}
				final PointerState ps = mPointers.get(id);
				ps.mVelocity = VelocityTracker.obtain();
				ps.mCurDown = true;
				if (mPrintCoords) {
					Log.i("Pointer", "Pointer " + (id + 1) + ": DOWN");
				}
			}

			final int NI = event.getPointerCount();// 获取触控点的数量,比如2则可能是两个手指同时按压屏幕

			mCurDown = action != MotionEvent.ACTION_UP
					&& action != MotionEvent.ACTION_CANCEL;
			mCurNumPointers = mCurDown ? NI : 0;
			if (mMaxNumPointers < mCurNumPointers) {
				mMaxNumPointers = mCurNumPointers;
			}

			for (int i = 0; i < NI; i++) {
				final int id = event.getPointerId(i);
				final PointerState ps = mPointers.get(id);
				ps.mVelocity.addMovement(event);
				ps.mVelocity.computeCurrentVelocity(1);
				final int N = event.getHistorySize();
				for (int j = 0; j < N; j++) {
					if (mPrintCoords) {
						Log.i("Pointer",
								"Pointer " + (id + 1) + ": ("
										+ event.getHistoricalX(i, j) + ", "
										+ event.getHistoricalY(i, j) + ")"
										+ " Prs="
										+ event.getHistoricalPressure(i, j)
										+ " Size="
										+ event.getHistoricalSize(i, j));
					}
					ps.mXs.add(event.getHistoricalX(i, j));
					ps.mYs.add(event.getHistoricalY(i, j));
				}
				if (mPrintCoords) {
					Log.i("Pointer",
							"Pointer " + (id + 1) + ": (" + event.getX(i)
									+ ", " + event.getY(i) + ")" + " Prs="
									+ event.getPressure(i) + " Size="
									+ event.getSize(i));
				}
				ps.mXs.add(event.getX(i));
				ps.mYs.add(event.getY(i));
				ps.mCurX = (int) event.getX(i);
				ps.mCurY = (int) event.getY(i);
				// Log.i("Pointer", "Pointer #" + p + ": (" + ps.mCurX
				// + "," + ps.mCurY + ")");
				ps.mCurPressure = event.getPressure(i);
				ps.mCurSize = event.getSize(i);
				ps.mCurWidth = (int) (ps.mCurSize * (getWidth() / 3));
			}

			if ((action & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_POINTER_UP) {
				final int index = (action & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
				final int id = event.getPointerId(index);
				final PointerState ps = mPointers.get(id);
				ps.mXs.add(Float.NaN);
				ps.mYs.add(Float.NaN);
				ps.mCurDown = false;
				if (mPrintCoords) {
					Log.i("Pointer", "Pointer " + (id + 1) + ": UP");
				}
			}

			if (action == MotionEvent.ACTION_UP) {
				for (int i = 0; i < NI; i++) {
					final int id = event.getPointerId(i);
					final PointerState ps = mPointers.get(id);
					if (ps.mCurDown) {
						ps.mCurDown = false;
						if (mPrintCoords) {
							Log.i("Pointer", "Pointer " + (id + 1) + ": UP");
						}
					}
				}
			}

			// if (mCurDown) {
			// mRect.union(mCurX-mCurWidth-3, mCurY-mCurWidth-3,
			// mCurX+mCurWidth+3, mCurY+mCurWidth+3);
			// }
			// invalidate(mRect);
			postInvalidate();
		}
	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		addTouchEvent(event);
		return true;
	}

	@Override
	public boolean onTrackballEvent(MotionEvent event) {
		Log.i("Pointer", "Trackball: " + event);
		return super.onTrackballEvent(event);
	}

}


PointerLocation.java:

public class PointerLocation extends Activity {
	@Override
	protected void onCreate(Bundle icicle) {
		super.onCreate(icicle);
		setContentView(new PointerLocationView(this));

		// Make the screen full bright for this activity.
		WindowManager.LayoutParams lp = getWindow().getAttributes();
		lp.screenBrightness = 1.0f;
		getWindow().setAttributes(lp);
	}
}

 


demo地址:http://download.csdn.net/detail/weiyirong/4969590

效果图:

你可能感兴趣的:(Android)