自定义View,1. 自定义一个Runnable线程TouchEventCountThread , 用来统计500ms内的点击次数
2. 在MyView中的 onTouchEvent 中调用 上面的线程
3. 自定义一个Handler, 在TouchEventHandler 中 处理 统计到的点击事件, 单击, 双击, 三击, 都可以处理
核心代码如下: public class MyView extends View {......// 统计500ms内的点击次数TouchEventCountThread mInTouchEventCount = new TouchEventCountThread();// 根据TouchEventCountThread统计到的点击次数, perform单击还是双击事件TouchEventHandler mTouchEventHandler = new TouchEventHandler();@Overridepublic boolean onTouchEvent(MotionEvent event) {switch (event.getAction()) {case MotionEvent.ACTION_DOWN:if (0 == mInTouchEventCount.touchCount) // 第一次按下时,开始统计postDelayed(mInTouchEventCount, 500);break;case MotionEvent.ACTION_UP:// 一次点击事件要有按下和抬起, 有抬起必有按下, 所以只需要在ACTION_UP中处理mInTouchEventCount.touchCount++;// 如果是长按操作, 则Handler的消息,不能将touchCount置0, 需要特殊处理if(mInTouchEventCount.isLongClick) {mInTouchEventCount.touchCount = 0;mInTouchEventCount.isLongClick = false;}break;case MotionEvent.ACTION_MOVE:break;case MotionEvent.ACTION_CANCEL:break;default:break;}return super.onTouchEvent(event);}public class TouchEventCountThread implements Runnable {public int touchCount = 0;public boolean isLongClick = false;@Overridepublic void run() {Message msg = new Message();if(0 == touchCount){ // long clickisLongClick = true;} else {msg.arg1 = touchCount;mTouchEventHandler.sendMessage(msg);touchCount = 0;}}}public class TouchEventHandler extends Handler {@Overridepublic void handleMessage(Message msg) {Toast.makeText(mContext, "touch " + msg.arg1 + " time.", Toast.LENGTH_SHORT).show();}}......}
包装以后如下, 这样就能在别的地方调用了:
public interface OnDoubleClickListener{void onDoubleClick(View v);}private OnDoubleClickListener mOnDoubleClickListener;public void setOnDoubleClickListener(MyView.OnDoubleClickListener l) {mOnDoubleClickListener = l;}public boolean performDoubleClick() {boolean result = false;if(mOnDoubleClickListener != null) {mOnDoubleClickListener.onDoubleClick(this);result = true;}return result;}public class TouchEventHandler extends Handler {@Overridepublic void handleMessage(Message msg) {if(2 == msg.arg1)performDoubleClick();}}
在Activity中使用:
myView1.setOnDoubleClickListener(new MyView.OnDoubleClickListener() {@Overridepublic void onDoubleClick(View v) {Toast.makeText(mContext,"double click", Toast.LENGTH_SHORT).show();}});
全部代码
MyView.javapackage com.carloz.test.myapplication.view;import android.content.Context;import android.content.res.TypedArray;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.graphics.Canvas;import android.graphics.Paint;import android.os.Handler;import android.os.Message;import android.util.AttributeSet;import android.view.MotionEvent;import android.view.View;import android.widget.Toast;import com.carloz.test.myapplication.R;/** * Created by root on 15-11-9. */public class MyView extends View {private Paint mPaint = new Paint();private boolean mNotDestroy = true;private int mCount = 0;private MyThread myThread;Bitmap bitmap;// attrsprivate String mText;private boolean mStartChange;Context mContext;public MyView(Context context) {super(context);init();}public MyView(Context context, AttributeSet attrs) {super(context, attrs);TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.MyView);mText = ta.getString(R.styleable.MyView_text);mStartChange = ta.getBoolean(R.styleable.MyView_startChange, false);// Log.d("ASDF", "mText=" + mText + ", mStartChange=" + mStartChange);ta.recycle();init();}@Overrideprotected void onFinishInflate() {super.onFinishInflate();}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);}@Overrideprotected void onLayout(boolean changed, int left, int top, int right, int bottom) {super.onLayout(changed, left, top, right, bottom);}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);mPaint.setTextSize(50);canvas.drawText(mText + mCount++, 20f, 100f, mPaint);canvas.save();canvas.rotate(60, getWidth() / 2, getHeight() / 2);canvas.drawBitmap(bitmap, 20f, 50f, mPaint);canvas.restore();if (null == myThread) {myThread = new MyThread();myThread.start();}}@Overridepublic boolean dispatchTouchEvent(MotionEvent ev) {return super.dispatchTouchEvent(ev);}@Overrideprotected void onAttachedToWindow() {super.onAttachedToWindow();mNotDestroy = true;}@Overrideprotected void onDetachedFromWindow() {mNotDestroy = false;super.onDetachedFromWindow();}// 统计500ms内的点击次数TouchEventCountThread mInTouchEventCount = new TouchEventCountThread();// 根据TouchEventCountThread统计到的点击次数, perform单击还是双击事件TouchEventHandler mTouchEventHandler = new TouchEventHandler();@Overridepublic boolean onTouchEvent(MotionEvent event) {switch (event.getAction()) {case MotionEvent.ACTION_DOWN:if (0 == mInTouchEventCount.touchCount) // 第一次按下时,开始统计postDelayed(mInTouchEventCount, 500);break;case MotionEvent.ACTION_UP:// 一次点击事件要有按下和抬起, 有抬起必有按下, 所以只需要在ACTION_UP中处理mInTouchEventCount.touchCount++;// 如果是长按操作, 则Handler的消息,不能将touchCount置0, 需要特殊处理if(mInTouchEventCount.isLongClick) {mInTouchEventCount.touchCount = 0;mInTouchEventCount.isLongClick = false;}break;case MotionEvent.ACTION_MOVE:break;case MotionEvent.ACTION_CANCEL:break;default:break;}return super.onTouchEvent(event);}public class TouchEventCountThread implements Runnable {public int touchCount = 0;public boolean isLongClick = false;@Overridepublic void run() {Message msg = new Message();if(0 == touchCount){ // long clickisLongClick = true;} else {msg.arg1 = touchCount;mTouchEventHandler.sendMessage(msg);touchCount = 0;}}}public class TouchEventHandler extends Handler {@Overridepublic void handleMessage(Message msg) {Toast.makeText(mContext, "touch " + msg.arg1 + " time.", Toast.LENGTH_SHORT).show();}}class MyThread extends Thread {@Overridepublic void run() {super.run();while (mNotDestroy) {if (mStartChange) {postInvalidate();try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}}}}}public void init() {mContext = getContext();bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);}public void setText(String mText) {this.mText = mText;}public void setStartChange(boolean mStartChange) {this.mStartChange = mStartChange;}public boolean getStartChange() {return this.mStartChange;}}
attrs.xml
<?xml version="1.0" encoding="utf-8"?><resources><declare-styleable name="MyView"><attr name="text" format="string"/><attr name="startChange" format="boolean"/></declare-styleable></resources>
postDelayed方法最终是靠 Handler 的 postDelayed 方法 实现原理如下
public final boolean postDelayed(Runnable r, long delayMillis){return sendMessageDelayed(getPostMessage(r), delayMillis);}public final boolean sendMessageDelayed(Message msg, long delayMillis){if (delayMillis < 0) {delayMillis = 0;}return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);}public boolean sendMessageAtTime(Message msg, long uptimeMillis) {MessageQueue queue = mQueue;if (queue == null) {RuntimeException e = new RuntimeException(this + " sendMessageAtTime() called with no mQueue");Log.w("Looper", e.getMessage(), e);return false;}return enqueueMessage(queue, msg, uptimeMillis); // 然后在MessageQueue中会比较时间顺序}
以上就是小编为大家带来的Android 自定义View实现单击和双击事件的方法的全部内容了,希望对大家有所帮助,多多支持脚本之家~