Android 自定義View實現(xiàn)單擊和雙擊事件的方法
自定義View,
1. 自定義一個Runnable線程TouchEventCountThread , 用來統(tǒng)計500ms內(nèi)的點擊次數(shù)
2. 在MyView中的 onTouchEvent 中調(diào)用 上面的線程
3. 自定義一個Handler, 在TouchEventHandler 中 處理 統(tǒng)計到的點擊事件, 單擊, 雙擊, 三擊, 都可以處理
核心代碼如下:
public class MyView extends View { ...... // 統(tǒng)計500ms內(nèi)的點擊次數(shù) TouchEventCountThread mInTouchEventCount = new TouchEventCountThread(); // 根據(jù)TouchEventCountThread統(tǒng)計到的點擊次數(shù), perform單擊還是雙擊事件 TouchEventHandler mTouchEventHandler = new TouchEventHandler(); @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: if (0 == mInTouchEventCount.touchCount) // 第一次按下時,開始統(tǒng)計 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(); } } ...... }
包裝以后如下, 這樣就能在別的地方調(diào)用了:
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(); } // 統(tǒng)計500ms內(nèi)的點擊次數(shù) TouchEventCountThread mInTouchEventCount = new TouchEventCountThread(); // 根據(jù)TouchEventCountThread統(tǒng)計到的點擊次數(shù), perform單擊還是雙擊事件 TouchEventHandler mTouchEventHandler = new TouchEventHandler(); @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: if (0 == mInTouchEventCount.touchCount) // 第一次按下時,開始統(tǒng)計 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 方法 實現(xiàn)原理如下
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中會比較時間順序 }
以上就是小編為大家?guī)淼腁ndroid 自定義View實現(xiàn)單擊和雙擊事件的方法的全部內(nèi)容了,希望對大家有所幫助,多多支持腳本之家~
- Android 單雙擊實現(xiàn)的方法步驟
- Android實現(xiàn)雙擊返回鍵退出應用實現(xiàn)方法詳解
- Android雙擊事件攔截方法
- Android使用PhotoView實現(xiàn)圖片雙擊放大單擊退出效果
- Android 雙擊Back鍵退出應用的實現(xiàn)方法
- Android實現(xiàn)雙擊TitleBar回頂部的功能示例代碼
- Android 雙擊返回鍵退出程序的方法總結
- Android 在viewPager中雙指縮放圖片雙擊縮放圖片單指拖拽圖片的實現(xiàn)思路
- Android中雙擊返回鍵退出應用實例代碼
- Android 高仿微信朋友圈動態(tài)支持雙擊手勢放大并滑動查看圖片效果
- Android 屏幕雙擊事件的捕獲簡單示例
- Android 實現(xiàn)雙擊退出的功能
- Android App中實現(xiàn)可以雙擊放大和縮小圖片功能的實例
- Android實現(xiàn)ImageView圖片雙擊放大及縮小
- Android雙擊退出的實現(xiàn)方法
- Android雙擊返回鍵退出程序的實現(xiàn)方法
- 使用python編寫android截屏腳本雙擊運行即可
- Android開發(fā)實現(xiàn)控件雙擊事件的監(jiān)聽接口封裝類
相關文章
Android UI自定義ListView實現(xiàn)下拉刷新和加載更多效果
這篇文章主要介紹了Android UI自定義ListView實現(xiàn)下拉刷新和加載更多效果,具有一定的參考價值,感興趣的小伙伴們可以參考一下2016-11-11Android音視頻開發(fā)之MediaCodec的使用教程
在Android開發(fā)中提供了實現(xiàn)音視頻編解碼工具MediaCodec,針對對應音視頻解碼類型通過該類創(chuàng)建對應解碼器就能實現(xiàn)對數(shù)據(jù)進行解碼操作。本文通過示例詳細講解了MediaCodec的使用,需要的可以參考一下2022-04-04Android基于OpenCV實現(xiàn)QR二維碼檢測
QR碼比普通一維條碼具有快速讀取和更大的存儲資料容量,也無需要像一維條碼般在掃描時需要直線對準掃描儀。因此其應用范圍已經(jīng)擴展到包括產(chǎn)品跟蹤,物品識別,文檔管理,庫存營銷等方面。本文講解Android基于OpenCV實現(xiàn)QR二維碼檢測的步驟2021-06-06android ListView內(nèi)數(shù)據(jù)的動態(tài)添加與刪除實例代碼
ListView內(nèi)數(shù)據(jù)的動態(tài)添加與刪除2013-03-03Android實現(xiàn)史上最簡單自定義開關按鈕的方法
在平常的開發(fā)中按鈕是經(jīng)常使用到的控件之一,下面這篇文章主要給大家介紹了關于Android實現(xiàn)史上最簡單自定義開關按鈕的相關資料,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下2022-04-04