现在的位置: 首页 > 综合 > 正文

Android自定义长按事件

2013年01月01日 ⁄ 综合 ⁄ 共 5994字 ⁄ 字号 评论关闭

 

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;  
    }  

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;  
    }  

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

抱歉!评论已关闭.