Android 自定義View實(shí)現(xiàn)單擊和雙擊事件的方法
自定義View,
1. 自定義一個(gè)Runnable線程TouchEventCountThread , 用來(lái)統(tǒng)計(jì)500ms內(nèi)的點(diǎn)擊次數(shù)
2. 在MyView中的 onTouchEvent 中調(diào)用 上面的線程
3. 自定義一個(gè)Handler, 在TouchEventHandler 中 處理 統(tǒng)計(jì)到的點(diǎn)擊事件, 單擊, 雙擊, 三擊, 都可以處理
核心代碼如下:
public class MyView extends View {
......
// 統(tǒng)計(jì)500ms內(nèi)的點(diǎn)擊次數(shù)
TouchEventCountThread mInTouchEventCount = new TouchEventCountThread();
// 根據(jù)TouchEventCountThread統(tǒng)計(jì)到的點(diǎn)擊次數(shù), perform單擊還是雙擊事件
TouchEventHandler mTouchEventHandler = new TouchEventHandler();
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
if (0 == mInTouchEventCount.touchCount) // 第一次按下時(shí),開(kāi)始統(tǒng)計(jì)
postDelayed(mInTouchEventCount, 500);
break;
case MotionEvent.ACTION_UP:
// 一次點(diǎn)擊事件要有按下和抬起, 有抬起必有按下, 所以只需要在ACTION_UP中處理
mInTouchEventCount.touchCount++;
// 如果是長(zhǎng)按操作, 則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)計(jì)500ms內(nèi)的點(diǎn)擊次數(shù)
TouchEventCountThread mInTouchEventCount = new TouchEventCountThread();
// 根據(jù)TouchEventCountThread統(tǒng)計(jì)到的點(diǎn)擊次數(shù), perform單擊還是雙擊事件
TouchEventHandler mTouchEventHandler = new TouchEventHandler();
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
if (0 == mInTouchEventCount.touchCount) // 第一次按下時(shí),開(kāi)始統(tǒng)計(jì)
postDelayed(mInTouchEventCount, 500);
break;
case MotionEvent.ACTION_UP:
// 一次點(diǎn)擊事件要有按下和抬起, 有抬起必有按下, 所以只需要在ACTION_UP中處理
mInTouchEventCount.touchCount++;
// 如果是長(zhǎng)按操作, 則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 方法 實(shí)現(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中會(huì)比較時(shí)間順序
}
以上就是小編為大家?guī)?lái)的Android 自定義View實(shí)現(xiàn)單擊和雙擊事件的方法的全部?jī)?nèi)容了,希望對(duì)大家有所幫助,多多支持腳本之家~
- Android 單雙擊實(shí)現(xiàn)的方法步驟
- Android實(shí)現(xiàn)雙擊返回鍵退出應(yīng)用實(shí)現(xiàn)方法詳解
- Android雙擊事件攔截方法
- Android使用PhotoView實(shí)現(xiàn)圖片雙擊放大單擊退出效果
- Android 雙擊Back鍵退出應(yīng)用的實(shí)現(xiàn)方法
- Android實(shí)現(xiàn)雙擊TitleBar回頂部的功能示例代碼
- Android 雙擊返回鍵退出程序的方法總結(jié)
- Android 在viewPager中雙指縮放圖片雙擊縮放圖片單指拖拽圖片的實(shí)現(xiàn)思路
- Android中雙擊返回鍵退出應(yīng)用實(shí)例代碼
- Android 高仿微信朋友圈動(dòng)態(tài)支持雙擊手勢(shì)放大并滑動(dòng)查看圖片效果
- Android 屏幕雙擊事件的捕獲簡(jiǎn)單示例
- Android 實(shí)現(xiàn)雙擊退出的功能
- Android App中實(shí)現(xiàn)可以雙擊放大和縮小圖片功能的實(shí)例
- Android實(shí)現(xiàn)ImageView圖片雙擊放大及縮小
- Android雙擊退出的實(shí)現(xiàn)方法
- Android雙擊返回鍵退出程序的實(shí)現(xiàn)方法
- 使用python編寫(xiě)android截屏腳本雙擊運(yùn)行即可
- Android開(kāi)發(fā)實(shí)現(xiàn)控件雙擊事件的監(jiān)聽(tīng)接口封裝類(lèi)
相關(guān)文章
Android Studio自動(dòng)提取控件Style樣式教程
這篇文章主要介紹了Android Studio自動(dòng)提取控件Style樣式教程,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-03-03
Android 日期和時(shí)間的使用實(shí)例詳解
這篇文章主要介紹了Android 日期和時(shí)間的使用實(shí)例詳解的相關(guān)資料,需要的朋友可以參考下2016-12-12
Android?studio實(shí)現(xiàn)app登錄界面
這篇文章主要為大家詳細(xì)介紹了Android?studio實(shí)現(xiàn)app登錄界面,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-04-04
Android如何用自定義View實(shí)現(xiàn)雪花效果
這篇文章主要介紹了Android如何用自定義View實(shí)現(xiàn)雪花效果,對(duì)特效感興趣的同學(xué)可以參考下2021-04-04
Android RecyclerView 復(fù)用錯(cuò)亂通用解法詳解
本篇文章主要介紹了Android RecyclerView 復(fù)用錯(cuò)亂通用解法詳解,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-08-08
Android使用內(nèi)置WebView打開(kāi)TextView超鏈接的實(shí)現(xiàn)方法
這篇文章主要介紹了Android使用內(nèi)置WebView打開(kāi)TextView超鏈接的實(shí)現(xiàn)方法,文中給出了詳細(xì)的示例代碼,對(duì)各位Android開(kāi)發(fā)者們具有一定的參考價(jià)值,需要的朋友們下面來(lái)一起看看吧。2017-03-03
Android DrawerLayout帶有側(cè)滑功能的布局類(lèi)(1)
這篇文章主要為大家詳細(xì)介紹了Android DrawerLayout帶有側(cè)滑功能的布局類(lèi),感興趣的小伙伴們可以參考一下2016-07-07

