zoukankan      html  css  js  c++  java
  • 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++;
                    // 如果是长按操作, 则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

    <?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>
    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中会比较时间顺序
        }
  • 相关阅读:
    php设计模式之桥接模式
    php设计模式适配器模式
    php设计模式之装饰器模式
    php设计模式之策略模式
    php设计模式之责任链模式
    Graphics.DrawString 方法
    算法7-10:拓扑排序
    一年成为Emacs高手(像神一样使用编辑器)
    动态规划0—1背包问题
    辛星解读为什么PHP须要模板
  • 原文地址:https://www.cnblogs.com/carlo/p/4960664.html
Copyright © 2011-2022 走看看