博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android 自定义View实现单击和双击事件
阅读量:6224 次
发布时间:2019-06-21

本文共 9175 字,大约阅读时间需要 30 分钟。

自定义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;    }}
View Code

 

attrs.xml

View Code

  

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中会比较时间顺序    }

 

转载地址:http://druna.baihongyu.com/

你可能感兴趣的文章
融入欧洲产业链 华为在数学上投注希望
查看>>
中国实现城域量子隐形传态为全球量子网络打基础
查看>>
超算入云
查看>>
沃达丰完成5G毫微波测试 室外单用户速率达到20Gbps
查看>>
Facebook宣布支持在Android上使用Tor访问
查看>>
即便背靠微信,微信企业号累积 2000 万用户也用了近两年时间
查看>>
MuleSoft发布新的Anypoint Platform,用户可操控API
查看>>
牙疼怎么快速止痛,三招解决牙痛立竿见影
查看>>
大数据云计算悄然改变服务器市场格局 英特尔霸主地位受IBM、ARM威胁
查看>>
英利宣布退出欧盟限价限协议
查看>>
深圳运用大数据推动"智慧司法"
查看>>
Windows 10免费升级服务终成历史 说说我们和它的恩怨
查看>>
苹果为何在中国一南一北设两个研发中心?五重考量
查看>>
Three UK遭黑客入侵 600万用户的个人信息存在被窃危险
查看>>
自动驾驶应有传感器冗余
查看>>
超融合产业需要这种“情怀”
查看>>
11-3URLTestDemo实例操作完成URL单元测试
查看>>
使用大数据,就像在沙子里淘金
查看>>
敏捷测试理论以及实践(4)
查看>>
Windows 10新版15058推送:RS2准正式、无水印
查看>>