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

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

  • 相关阅读:
    iOS开发之Quartz2D 二:绘制直线,曲线,圆弧,矩形,椭圆,圆
    统计英文文章中各单词的频率,打印频率最高的十个单词(C语言实现)
    Android protectionLevel
    nmon for linux
    UFT 小技巧
    adb测试使用相关
    Java 反射
    Android USB安全调试
    android.process.acore和system进程
    Android 屏幕截图
  • 原文地址:https://www.cnblogs.com/greywolf/p/2831271.html
Copyright © 2020-2023  润新知