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

自定义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++;                break;
            case MotionEvent.ACTION_MOVE:
                break;
            case MotionEvent.ACTION_CANCEL:
                break;
            default:
                break;
        }

        return super.onTouchEvent(event);
    }

    public class TouchEventHandler extends Handler {

        @Override
        public void handleMessage(Message msg) {
            Toast.makeText(mContext, "touch " + msg.arg1 + " time.", Toast.LENGTH_SHORT).show();
        }
    }

    public class TouchEventCountThread implements Runnable {
        public int touchCount = 0;

        @Override
        public void run() {
            Message msg = new Message();
            msg.arg1 = touchCount;
            mTouchEventHandler.sendMessage(msg);
            touchCount = 0;
        }
    }

   ......
}

全部代码

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.util.Log;
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++; //
                break;
            case MotionEvent.ACTION_MOVE:
                break;
            case MotionEvent.ACTION_CANCEL:
                break;
            default:
                break;
        }

        return super.onTouchEvent(event);
    }

    public class TouchEventHandler extends Handler {

        @Override
        public void handleMessage(Message msg) {
            Toast.makeText(mContext, "touch " + msg.arg1 + " time.", Toast.LENGTH_SHORT).show();
        }
    }

    public class TouchEventCountThread implements Runnable {
        public int touchCount = 0;

        @Override
        public void run() {
            Message msg = new Message();
            msg.arg1 = touchCount;
            mTouchEventHandler.sendMessage(msg);
            touchCount = 0;
        }
    }

    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;
    }
}

时间: 2024-10-05 21:50:48

Android 自定义View实现单击和双击事件的相关文章

android 自定义view,绘制与onTouchEvent事件(一)

绘制 构造方法 自定义view需要继承View类,重写两个构造方法 //用在代码new该view对象,初始化 public MyView(Context context) { super(context); init(); } //一般添加构造--->view放进布局,系统实例化 public MyView(Context context, AttributeSet attrs) { super(context, attrs); init(); } Paint对象 绘制view需要使用Paint

Android 自定义View——自定义点击事件

每个人手机上都有通讯录,这是毫无疑问的,我们通讯录上有一个控件,在通讯录的最左边有一列从"#"到"Z"的字母,我们通过滑动或点击指定的字母来确定联系人的位置,进而找到联系人.我们这一节就通过开发这个控件,来学如何自定义控件的点击事件. 通讯录列表查找控件界面绘制 首先我们需要先将控件的基本布局绘制出来,这里我们不在做详细的解释,在<Android 自定义View--自定义View控件 >博客中,我们已经详细讲解了如何绘制自定义控件的布局.通讯录列表查找控

【朝花夕拾】Android自定义View篇之(六)Android事件分发机制(中)从源码分析事件分发逻辑及经常遇到的一些“诡异”现象

前言 转载请注明,转自[https://www.cnblogs.com/andy-songwei/p/11039252.html]谢谢! 在上一篇文章[[朝花夕拾]Android自定义View篇之(五)Android事件分发机制(上)Touch三个重要方法的处理逻辑][下文简称(五),请先阅读完(五)再阅读本文],我们通过示例和log来分析了Android的事件分发机制.这些,我们只是看到了现象,如果要进一步了解事件分发机制,这是不够的,我们还需要透过现象看本质,去研究研究源码.本文将从源码(基

(转)[原] Android 自定义View 密码框 例子

遵从准则 暴露您view中所有影响可见外观的属性或者行为. 通过XML添加和设置样式 通过元素的属性来控制其外观和行为,支持和重要事件交流的事件监听器 详细步骤见:Android 自定义View步骤 样子 支持的样式 可以通过XML定义影响外边和行为的属性如下 边框圆角值,边框颜色,分割线颜色,边框宽度,密码长度,密码大小,密码颜色 <declare-styleable name="PasswordInputView"> <attr name="border

Android自定义View——圆形进度条式按钮

介绍 今天上班的时候有个哥们问我怎么去实现一个按钮式的进度条,先来看看他需要实现的效果图. 和普通的圆形进度条类似,只是中间的地方有两个状态表示,未开始,暂停状态.而且他说圆形进度的功能已经实现了.那么我们只需要对中间的两个状态做处理就行了. 先来看看实现的效果图: 上面说了我们只需要处理中间状态的变化就可以了,对于进度的处理直接使用了弘洋文章中实现: http://blog.csdn.net/lmj623565791/article/details/43371299 下面开始具体实现. 具体实

[原] Android 自定义View 密码框 例子

遵从准则 暴露您view中所有影响可见外观的属性或者行为. 通过XML添加和设置样式 通过元素的属性来控制其外观和行为,支持和重要事件交流的事件监听器 详细步骤见:Android 自定义View步骤 样子 支持的样式 可以通过XML定义影响外边和行为的属性如下 边框圆角值,边框颜色,分割线颜色,边框宽度,密码长度,密码大小,密码颜色 <declare-styleable name="PasswordInputView"> <attr name="border

[原] Android 自定义View步骤

例子如下:Android 自定义View 密码框 例子 1 良好的自定义View 易用,标准,开放. 一个设计良好的自定义view和其他设计良好的类很像.封装了某个具有易用性接口的功能组合,这些功能能够有效地使用CPU和内存,并且十分开放的.但是,除了开始一个设计良好的类之外,一个自定义view应该: l 符合安卓标准 l 提供能够在Android XML布局中工作的自定义样式属性 l 发送可访问的事件 l 与多个Android平台兼容. Android框架提供了一套基本的类和XML标签来帮您创

Android自定义View(CustomCalendar-定制日历控件)

转载请标明出处: http://blog.csdn.net/xmxkf/article/details/54020386 本文出自:[openXu的博客] 目录: 1分析 2自定义属性 3onMeasure 4onDraw 绘制月份 绘制星期 绘制日期及任务 5事件处理 源码下载 ??应项目需求,需要做一个日历控件,效果图如下: ???? ??接到需求后,没有立即查找是否有相关开源日历控件可用.系统日历控件是否能满足 ,第一反应就是这个控件该怎么画?谁叫咱自定义控件技术牛逼呢O(∩_∩)O哈哈~

我的Android进阶之旅------&gt;Android自定义View实现带数字的进度条(NumberProgressBar)

今天在Github上面看到一个来自于 daimajia所写的关于Android自定义View实现带数字的进度条(NumberProgressBar)的精彩案例,在这里分享给大家一起来学习学习!同时感谢daimajia的开源奉献! 第一步.效果展示 图1.蓝色的进度条 图2.红色的进度条 图3.多条颜色不同的进度条 图4.多条颜色不同的进度条 版权声明:本文为[欧阳鹏]原创文章,欢迎转载,转载请注明出处! [http://blog.csdn.net/ouyang_peng/article/deta