Android自定义长按事件

    Android系统自带了长按事件,setOnLongClickListener即可监听。但是有时候,你不希望用系统的长按事件,比如当希望长按的时间更长一点的时候。这时候就需要自己来定义这个长按事件了。
    下面是去年我写代码的时候,自定义长按事件的方式:

Java代码 复制代码  收藏代码
  1. package chroya.fun;   
  2.   
  3. import android.content.Context;   
  4. import android.view.MotionEvent;   
  5. import android.view.View;   
  6. import android.view.ViewConfiguration;   
  7.   
  8. public class LongPressView1 extends View{   
  9.     private int mLastMotionX, mLastMotionY;   
  10.     //是否移动了   
  11.     private boolean isMoved;   
  12.     //是否释放了   
  13.     private boolean isReleased;   
  14.     //计数器,防止多次点击导致最后一次形成longpress的时间变短   
  15.     private int mCounter;   
  16.     //长按的runnable   
  17.     private Runnable mLongPressRunnable;   
  18.     //移动的阈值   
  19.     private static final int TOUCH_SLOP = 20;   
  20.   
  21.     public LongPressView1(Context context) {   
  22.         super(context);   
  23.         mLongPressRunnable = new Runnable() {   
  24.                
  25.             @Override  
  26.             public void run() {   
  27.                 mCounter--;   
  28.                 //计数器大于0,说明当前执行的Runnable不是最后一次down产生的。   
  29.                 if(mCounter>0 || isReleased || isMoved) return;   
  30.                 performLongClick();   
  31.             }   
  32.         };   
  33.     }   
  34.   
  35.     public boolean dispatchTouchEvent(MotionEvent event) {   
  36.         int x = (int) event.getX();   
  37.         int y = (int) event.getY();   
  38.            
  39.         switch(event.getAction()) {   
  40.         case MotionEvent.ACTION_DOWN:   
  41.             mLastMotionX = x;   
  42.             mLastMotionY = y;   
  43.             mCounter++;   
  44.             isReleased = false;   
  45.             isMoved = false;   
  46.             postDelayed(mLongPressRunnable, ViewConfiguration.getLongPressTimeout());   
  47.             break;   
  48.         case MotionEvent.ACTION_MOVE:   
  49.             if(isMoved) break;   
  50.             if(Math.abs(mLastMotionX-x) > TOUCH_SLOP    
  51.                     || Math.abs(mLastMotionY-y) > TOUCH_SLOP) {   
  52.                 //移动超过阈值,则表示移动了   
  53.                 isMoved = true;   
  54.             }   
  55.             break;   
  56.         case MotionEvent.ACTION_UP:   
  57.             //释放了   
  58.             isReleased = true;   
  59.             break;   
  60.         }   
  61.         return true;   
  62.     }   
  63. }  
package chroya.fun;

import android.content.Context;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;

public class LongPressView1 extends View{
	private int mLastMotionX, mLastMotionY;
	//是否移动了
	private boolean isMoved;
	//是否释放了
	private boolean isReleased;
	//计数器,防止多次点击导致最后一次形成longpress的时间变短
	private int mCounter;
	//长按的runnable
	private Runnable mLongPressRunnable;
	//移动的阈值
	private static final int TOUCH_SLOP = 20;

	public LongPressView1(Context context) {
		super(context);
		mLongPressRunnable = new Runnable() {
			
			@Override
			public void run() {
				mCounter--;
				//计数器大于0,说明当前执行的Runnable不是最后一次down产生的。
				if(mCounter>0 || isReleased || isMoved) return;
				performLongClick();
			}
		};
	}

	public boolean dispatchTouchEvent(MotionEvent event) {
		int x = (int) event.getX();
		int y = (int) event.getY();
		
		switch(event.getAction()) {
		case MotionEvent.ACTION_DOWN:
			mLastMotionX = x;
			mLastMotionY = y;
			mCounter++;
			isReleased = false;
			isMoved = false;
			postDelayed(mLongPressRunnable, ViewConfiguration.getLongPressTimeout());
			break;
		case MotionEvent.ACTION_MOVE:
			if(isMoved) break;
			if(Math.abs(mLastMotionX-x) > TOUCH_SLOP 
					|| Math.abs(mLastMotionY-y) > TOUCH_SLOP) {
				//移动超过阈值,则表示移动了
				isMoved = true;
			}
			break;
		case MotionEvent.ACTION_UP:
			//释放了
			isReleased = true;
			break;
		}
		return true;
	}
}

     代码里注释的比较清楚。主要思路是在down的时候,让一个Runnable一段时间后执行,如果时间到了,没有移动超过定义的阈值,也没有释放,则触发长按事件。在真实环境中,当长按触发之后,还需要将后来的move和up事件屏蔽掉。此处是示例,就略去了。

      下面讲讲第二种方式:

Java代码 复制代码  收藏代码
  1. package chroya.fun;   
  2.   
  3. import android.content.Context;   
  4. import android.view.MotionEvent;   
  5. import android.view.View;   
  6. import android.view.ViewConfiguration;   
  7.   
  8. public class LongPressView2 extends View{   
  9.     private int mLastMotionX, mLastMotionY;   
  10.     //是否移动了   
  11.     private boolean isMoved;   
  12.     //长按的runnable   
  13.     private Runnable mLongPressRunnable;   
  14.     //移动的阈值   
  15.     private static final int TOUCH_SLOP = 20;   
  16.   
  17.     public LongPressView2(Context context) {   
  18.         super(context);   
  19.         mLongPressRunnable = new Runnable() {   
  20.                
  21.             @Override  
  22.             public void run() {                
  23.                 performLongClick();   
  24.             }   
  25.         };   
  26.     }   
  27.   
  28.     public boolean dispatchTouchEvent(MotionEvent event) {   
  29.         int x = (int) event.getX();   
  30.         int y = (int) event.getY();   
  31.            
  32.         switch(event.getAction()) {   
  33.         case MotionEvent.ACTION_DOWN:   
  34.             mLastMotionX = x;   
  35.             mLastMotionY = y;   
  36.             isMoved = false;   
  37.             postDelayed(mLongPressRunnable, ViewConfiguration.getLongPressTimeout());   
  38.             break;   
  39.         case MotionEvent.ACTION_MOVE:   
  40.             if(isMoved) break;   
  41.             if(Math.abs(mLastMotionX-x) > TOUCH_SLOP    
  42.                     || Math.abs(mLastMotionY-y) > TOUCH_SLOP) {   
  43.                 //移动超过阈值,则表示移动了   
  44.                 isMoved = true;   
  45.                 removeCallbacks(mLongPressRunnable);   
  46.             }   
  47.             break;   
  48.         case MotionEvent.ACTION_UP:   
  49.             //释放了   
  50.             removeCallbacks(mLongPressRunnable);   
  51.             break;   
  52.         }   
  53.         return true;   
  54.     }   
  55. }  
package chroya.fun;

import android.content.Context;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;

public class LongPressView2 extends View{
	private int mLastMotionX, mLastMotionY;
	//是否移动了
	private boolean isMoved;
	//长按的runnable
	private Runnable mLongPressRunnable;
	//移动的阈值
	private static final int TOUCH_SLOP = 20;

	public LongPressView2(Context context) {
		super(context);
		mLongPressRunnable = new Runnable() {
			
			@Override
			public void run() {				
				performLongClick();
			}
		};
	}

	public boolean dispatchTouchEvent(MotionEvent event) {
		int x = (int) event.getX();
		int y = (int) event.getY();
		
		switch(event.getAction()) {
		case MotionEvent.ACTION_DOWN:
			mLastMotionX = x;
			mLastMotionY = y;
			isMoved = false;
			postDelayed(mLongPressRunnable, ViewConfiguration.getLongPressTimeout());
			break;
		case MotionEvent.ACTION_MOVE:
			if(isMoved) break;
			if(Math.abs(mLastMotionX-x) > TOUCH_SLOP 
					|| Math.abs(mLastMotionY-y) > TOUCH_SLOP) {
				//移动超过阈值,则表示移动了
				isMoved = true;
				removeCallbacks(mLongPressRunnable);
			}
			break;
		case MotionEvent.ACTION_UP:
			//释放了
			removeCallbacks(mLongPressRunnable);
			break;
		}
		return true;
	}
}

     思路跟第一种差不多,不过,在移动超过阈值和释放之后,会将Runnable从事件队列中remove掉,长按事件也就不会再触发了。源码中实现长按的原理也基本如此。

 

      工程见附件。


http://chroya.iteye.com/blog/804706

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值