以前一直都是看别人的的文章,自己从来还没写过,这次还是第一次写文章,最近项目中遇到个问题需要处理多次连续点击事件,所以在这里分享出来,效果基本实现了,但是不知道好不好,希望大家看看,有什么不对的地方指出来。
android本身自带的事件只能处理单击、长按事件,对于双击事件则需要通过手势来判断(参考GestureDetector),我今天在这里实现的方案主要是通过重写OnTouch事件是来实现,首先大家必须了解android的Touch事件,这里不去研究OnTouch事件和OnClick以及OnLongClick的机制了,也不去研究OnTouch的DOWN,MOVE,UP等事件了,相信大家对这方面有一定的了解了,好了进入正题。
1.连续点击事件 要实现多击判断我的思路是记录点击的次数,也就是在Down的时候对点击次数+1,在Up的时候开启一个线程来等待是否在短时间内有下一次点击到来。所以我定义了连续点击间隔时间为
private static final long CLICK_SPACING_TIME = 300;
这里利用Handler来让这个线程延迟300ms执行,如果在线程还没有开始执行之前又一Down事件来了,那么我在Handler的队列中删除这个线程,然后再Up里面重新往Handler里面添加一个线程来执行,这样就完成了间隔时间的等待,线程里面处理逻辑非常简单,就是把点击次数清空,然后回调一共连续点击了多少次。
public class ClickPressedThread implements Runnable{
@Override
public void run() {
mClickCount = 0;
}
}
2.长按事件
处理长按事件和连续点击事件思路相同,不同的是在Down的时候我开启一个线程然后延迟500ms(长按触发的时间)后执行,然后再UP的时候我判断如果按住的时间没有超过了500ms那么代码长按事件没有触发,然后执行连续点击事件的逻辑,同时删除掉Handler队列中的处理长按事件的线程,如果执行了Move事件也需要删除Handler队列里面的长按处理线程。
完整代码如下:
import java.util.Calendar;
import android.os.Handler;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
public class EasyTouchListener implements OnTouchListener{
private static final long CLICK_SPACING_TIME = 300;
private static final long LONG_PRESS_TIME = 500;
/**
* 当前触摸点相对于屏幕的坐标
*/
private int mCurrentInScreenX;
private int mCurrentInScreenY;
/**
* 触摸点按下时的相对于屏幕的坐标
*/
private int mDownInScreenX;
private int mDownInScreenY;
/**
* 点击次数
*/
private int mClickCount = 0;
/**
* 当前点击时间
*/
private long mCurrentClickTime;
private Handler mBaseHandler = new Handler();
/**
* 长按线程
*/
private LongPressedThread mLongPressedThread;
/**
* 点击等待线程
*/
private ClickPressedThread mPrevClickThread;
@Override
public boolean onTouch(View v, MotionEvent event) {
//获取相对屏幕的坐标,即以屏幕左上角为原点
mCurrentInScreenX = (int)event.getRawX();
mCurrentInScreenY = (int)event.getRawY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
//记录Down下时的坐标
mDownInScreenX = (int)event.getRawX();
mDownInScreenY = (int)event.getRawY();
//记录当前点击的时间
mCurrentClickTime = Calendar.getInstance().getTimeInMillis();
//点击次数加1
mClickCount++;
//取消上一次点击的线程
if(mPrevClickThread != null){
mBaseHandler.removeCallbacks(mPrevClickThread);
}
mLongPressedThread = new LongPressedThread();
mBaseHandler.postDelayed(mLongPressedThread,LONG_PRESS_TIME);
break;
case MotionEvent.ACTION_MOVE: {
mClickCount = 0; // 只要移动了 就没有点击事件了
//取消注册的长按事件
mBaseHandler.removeCallbacks(mLongPressedThread);
break;
}
case MotionEvent.ACTION_UP: {
if(!this.isMoved()){
//如果按住的时间超过了长按时间,那么其实长按事件已经出发生了,这个时候把数据清零
if(Calendar.getInstance().getTimeInMillis() - mCurrentClickTime <= LONG_PRESS_TIME){
//取消注册的长按事件
mBaseHandler.removeCallbacks(mLongPressedThread);
mPrevClickThread = new ClickPressedThread();
mBaseHandler.postDelayed(mPrevClickThread,CLICK_SPACING_TIME);
}
}else{
//UP的时候Move过
}
break;
}
default : break;
}
return true;
}
/**
* 判断是否移动
* @return
*/
private boolean isMoved(){
//允许有5的偏差 在判断是否移动的时候
if(Math.abs(mDownInScreenX - mCurrentInScreenX) <= 5 && Math.abs(mDownInScreenY - mCurrentInScreenY) <= 5 ){
return false;
}else{
return true;
}
}
public class LongPressedThread implements Runnable{
@Override
public void run() {
//这里处理长按事件
mClickCount = 0;
}
}
public class ClickPressedThread implements Runnable{
@Override
public void run() {
//这里处理连续点击事件 mClickCount 为连续点击的次数
mClickCount = 0;
}
}
}
PS:吐槽下第一次写博客保存的时候就遇到503,504了 衰!!!!