首页 > 系统 > Android > 正文

Android 自定义View实现单击和双击事件的方法

2019-12-12 05:08:58
字体:
来源:转载
供稿:网友

自定义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();  @Override  public 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;    @Override    public void run() {      Message msg = new Message();      if(0 == touchCount){ // long click        isLongClick = true;      } else {        msg.arg1 = touchCount;        mTouchEventHandler.sendMessage(msg);        touchCount = 0;      }    }  }  public class TouchEventHandler extends Handler {    @Override    public 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 {    @Override    public void handleMessage(Message msg) {      if(2 == msg.arg1)        performDoubleClick();    }  }

在Activity中使用

myView1.setOnDoubleClickListener(new MyView.OnDoubleClickListener() {  @Override  public void onDoubleClick(View v) {  Toast.makeText(mContext,"double click", Toast.LENGTH_SHORT).show();  }});

全部代码

MyView.java

package 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;  // attrs  private 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();  }  @Override  protected void onFinishInflate() {    super.onFinishInflate();  }  @Override  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {    super.onMeasure(widthMeasureSpec, heightMeasureSpec);  }  @Override  protected void onLayout(boolean changed, int left, int top, int right, int bottom) {    super.onLayout(changed, left, top, right, bottom);  }  @Override  protected 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();    }  }  @Override  public boolean dispatchTouchEvent(MotionEvent ev) {    return super.dispatchTouchEvent(ev);  }  @Override  protected void onAttachedToWindow() {    super.onAttachedToWindow();    mNotDestroy = true;  }  @Override  protected void onDetachedFromWindow() {    mNotDestroy = false;    super.onDetachedFromWindow();  }  // 统计500ms内的点击次数  TouchEventCountThread mInTouchEventCount = new TouchEventCountThread();  // 根据TouchEventCountThread统计到的点击次数, perform单击还是双击事件  TouchEventHandler mTouchEventHandler = new TouchEventHandler();  @Override  public 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;    @Override    public void run() {      Message msg = new Message();      if(0 == touchCount){ // long click        isLongClick = true;      } else {        msg.arg1 = touchCount;        mTouchEventHandler.sendMessage(msg);        touchCount = 0;      }    }  }  public class TouchEventHandler extends Handler {    @Override    public void handleMessage(Message msg) {      Toast.makeText(mContext, "touch " + msg.arg1 + " time.", Toast.LENGTH_SHORT).show();    }  }  class MyThread extends Thread {    @Override    public 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实现单击和双击事件的方法的全部内容了,希望对大家有所帮助,多多支持武林网~

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表