`
chroya
  • 浏览: 656285 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

Android自定义长按事件

阅读更多

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

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事件屏蔽掉。此处是示例,就略去了。

      下面讲讲第二种方式:

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掉,长按事件也就不会再触发了。源码中实现长按的原理也基本如此。

 

      工程见附件。

分享到:
评论
28 楼 Badwaka 2015-12-02  
Badwaka 写道
大神你太厉害了!


这个思路很特别,直接控制longClick事件的分发
我之前一直想着自己来做判定,很麻烦很麻烦,想的脑子都爆炸了。。。

谢谢大神~~~~
27 楼 Badwaka 2015-12-02  
大神你太厉害了!
26 楼 lanroness 2014-05-21  
lanroness 写道
打开是黑屏啊

就在屏幕上按么?为什么不弄个按钮呢
25 楼 lanroness 2014-05-21  
打开是黑屏啊
24 楼 zhaoyazhong 2013-10-31  
最近在做MapView相关的东西,长按,移动,点击相互影响,文章太有用了。桑扣!
23 楼 chroya 2012-09-24  
sayyanfu 写道
chroya 写道
热血pk007 写道
chroya 写道
热血pk007 写道
这个运行之后怎么是黑屏?触屏没反应啊

你看代码啊,log里面会打出来的。

长按时间也没有加长啊,和内部自带的长按事件是相同的时间长短啊

是的,长按事件是用的系统的时间ViewConfiguration.getLongPressTimeout(),如果你需要加长,可以自己更改,把这个改成想要的时间。

ViewConfiguration.getLongPressTimeout()是个常量如何修改?

sayyanfu 写道
chroya 写道
热血pk007 写道
chroya 写道
热血pk007 写道
这个运行之后怎么是黑屏?触屏没反应啊

你看代码啊,log里面会打出来的。

长按时间也没有加长啊,和内部自带的长按事件是相同的时间长短啊

是的,长按事件是用的系统的时间ViewConfiguration.getLongPressTimeout(),如果你需要加长,可以自己更改,把这个改成想要的时间。

ViewConfiguration.getLongPressTimeout()是个常量如何修改?

我不是说改ViewConfiguration.getLongPressTimeout()它的值,而是说自己定义长按delay的时间
22 楼 sayyanfu 2012-09-10  
chroya 写道
热血pk007 写道
chroya 写道
热血pk007 写道
这个运行之后怎么是黑屏?触屏没反应啊

你看代码啊,log里面会打出来的。

长按时间也没有加长啊,和内部自带的长按事件是相同的时间长短啊

是的,长按事件是用的系统的时间ViewConfiguration.getLongPressTimeout(),如果你需要加长,可以自己更改,把这个改成想要的时间。

ViewConfiguration.getLongPressTimeout()是个常量如何修改?
21 楼 chroya 2012-07-11  
ysxmwyhh 写道
请问我怎么在自己的button上面使用这个长按事件

自己的Button实现文中所述的几个方法,然后直接setOnLongClickListener即可。
20 楼 ysxmwyhh 2012-07-04  
请问我怎么在自己的button上面使用这个长按事件
19 楼 chroya 2011-12-31  
Dr.hydra 写道
感谢楼主!非常感谢,最近在做一个东西,正好遇到一个长按滑动和普通滑动并存的问题,幸亏看到楼主的文章!楼主能留个联系方式不,以后想向您请教

加群:5838954
18 楼 Dr.hydra 2011-12-07  
感谢楼主!非常感谢,最近在做一个东西,正好遇到一个长按滑动和普通滑动并存的问题,幸亏看到楼主的文章!楼主能留个联系方式不,以后想向您请教
17 楼 u_xtian 2011-10-13  
很不错!但是我现在需要自定义AdapterView里面的OnItemLongClickListener,难搞啊
16 楼 王山而 2011-08-08  
mark 
15 楼 greenboy1 2011-05-16  
楼主的文章不错
14 楼 chroya 2011-02-22  
binggo2011 写道
chroya 写道
binggo2011 写道
在onTOuch里面监听action-move执行的次数也可以实现longclick,
不知道有没意义,性能怎么样?

  不明白,监听action-move执行次数有什么作用?多少次算是longclick?


/**
* 自定义图片左右手势和类LongClick触发事件
* @author Administrator
*
*/
public abstract class MyOnTouchListener implements OnTouchListener {

private static final int MOVE_MIN_DISTANCE = 100; //触发左移或右移的最小距离
private static final int LONG_CLICK_MIN_DISTANCE = 20; //触发LongClick的最大移动距离
private static final int LONG_CLICK_MIN_TIME = 35; //触发LongClick的最小ACTION_MOVE的次数
private float mX;
private int mNum = 0;

public abstract void setLeftEvent();

public abstract void setRightEvent();

public abstract void setLongClickEvent();

@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mX = event.getX();
return false;
case MotionEvent.ACTION_CANCEL:

return false;
case MotionEvent.ACTION_MOVE:
System.out.println("MOVE");
mNum++;
return false;
case MotionEvent.ACTION_OUTSIDE:

return false;
case MotionEvent.ACTION_UP:
float distance = event.getX() - mX;
if (Math.abs(distance) > MOVE_MIN_DISTANCE) {
if (distance > 0)
setRightEvent();
else
setLeftEvent();
} else if (Math.abs(distance) < LONG_CLICK_MIN_DISTANCE
&& mNum > LONG_CLICK_MIN_TIME) {
setLongClickEvent();
}
mNum = 0;
return true;
}
return false;
}
}

我哥介绍看你的博客的  说看了能变超人的... 呃.

根据次数判断长按,太不严谨了 
别被误导了
13 楼 binggo2011 2011-02-22  
chroya 写道
binggo2011 写道
在onTOuch里面监听action-move执行的次数也可以实现longclick,
不知道有没意义,性能怎么样?

  不明白,监听action-move执行次数有什么作用?多少次算是longclick?


/**
* 自定义图片左右手势和类LongClick触发事件
* @author Administrator
*
*/
public abstract class MyOnTouchListener implements OnTouchListener {

private static final int MOVE_MIN_DISTANCE = 100; //触发左移或右移的最小距离
private static final int LONG_CLICK_MIN_DISTANCE = 20; //触发LongClick的最大移动距离
private static final int LONG_CLICK_MIN_TIME = 35; //触发LongClick的最小ACTION_MOVE的次数
private float mX;
private int mNum = 0;

public abstract void setLeftEvent();

public abstract void setRightEvent();

public abstract void setLongClickEvent();

@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mX = event.getX();
return false;
case MotionEvent.ACTION_CANCEL:

return false;
case MotionEvent.ACTION_MOVE:
System.out.println("MOVE");
mNum++;
return false;
case MotionEvent.ACTION_OUTSIDE:

return false;
case MotionEvent.ACTION_UP:
float distance = event.getX() - mX;
if (Math.abs(distance) > MOVE_MIN_DISTANCE) {
if (distance > 0)
setRightEvent();
else
setLeftEvent();
} else if (Math.abs(distance) < LONG_CLICK_MIN_DISTANCE
&& mNum > LONG_CLICK_MIN_TIME) {
setLongClickEvent();
}
mNum = 0;
return true;
}
return false;
}
}

我哥介绍看你的博客的  说看了能变超人的... 呃.
12 楼 chroya 2011-02-21  
binggo2011 写道
在onTOuch里面监听action-move执行的次数也可以实现longclick,
不知道有没意义,性能怎么样?

  不明白,监听action-move执行次数有什么作用?多少次算是longclick?
11 楼 binggo2011 2011-02-21  
在onTOuch里面监听action-move执行的次数也可以实现longclick,
不知道有没意义,性能怎么样?
10 楼 alen456 2010-12-06  
长按键,我之前也做过了,但是感觉你的代码比我的少点,感谢你!
9 楼 chroya 2010-12-05  
热血pk007 写道
chroya 写道
热血pk007 写道
这个运行之后怎么是黑屏?触屏没反应啊

你看代码啊,log里面会打出来的。

长按时间也没有加长啊,和内部自带的长按事件是相同的时间长短啊

是的,长按事件是用的系统的时间ViewConfiguration.getLongPressTimeout(),如果你需要加长,可以自己更改,把这个改成想要的时间。

相关推荐

Global site tag (gtag.js) - Google Analytics