职业IT人-IT人生活圈

 找回密码
 成为会员
搜索
查看: 1637|回复: 10

Android自定义长按事件

  [复制链接]
天上智喜 发表于 2011-6-23 10:43 | 显示全部楼层 |阅读模式
     Android系统自带了长按事件,setOnLongClickListener即可监听。但是有时候,你不希望用系统的长按事件,比如当希望长按的时间更长一点的时候。这时候就需要自己来定义这个长按事件了。
    下面是去年我写代码的时候,自定义长按事件的方式:
Java代码  
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事件屏蔽掉。此处是示例,就略去了。

      下面讲讲第二种方式:
Java代码  
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掉,长按事件也就不会再触发了。源码中实现长按的原理也基本如此。

话说我当年 发表于 2011-6-23 10:44 | 显示全部楼层
楼主可以提供源码下载不?好学习下,谢谢

broken 发表于 2011-6-23 10:44 | 显示全部楼层
能否与我们一起分享源码呢?

jinchang 发表于 2011-6-23 10:44 | 显示全部楼层
不错,谢谢

已经来了吗 发表于 2011-6-23 10:44 | 显示全部楼层
热血pk007 写道
楼主可以提供源码下载不?好学习下,谢谢

源码已附上。

话说我当年 发表于 2011-6-23 10:44 | 显示全部楼层
这个运行之后怎么是黑屏?触屏没反应啊

ksdal 发表于 2011-6-23 10:44 | 显示全部楼层
热血pk007 写道
这个运行之后怎么是黑屏?触屏没反应啊

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

 楼主| 天上智喜 发表于 2011-6-23 10:45 | 显示全部楼层
chroya 写道
热血pk007 写道
这个运行之后怎么是黑屏?触屏没反应啊

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

什么都没有啊

yoyo 发表于 2011-6-23 10:45 | 显示全部楼层
chroya 写道
热血pk007 写道
这个运行之后怎么是黑屏?触屏没反应啊

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

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

紫衿 发表于 2011-6-23 10:45 | 显示全部楼层
热血pk007 写道
chroya 写道
热血pk007 写道
这个运行之后怎么是黑屏?触屏没反应啊

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

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

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


qnajpfzu 发表于 2012-5-29 16:15 | 显示全部楼层

支持!

看贴不回贴 都什么习惯呀?


















唐绵防辐射服
您需要登录后才可以回帖 登录 | 成为会员

本版积分规则

QQ|手机版|小黑屋|网站帮助|职业IT人-IT人生活圈 ( 粤ICP备12053935号-1 )|网站地图
本站文章版权归原发布者及原出处所有。内容为作者个人观点,并不代表本站赞同其观点和对其真实性负责,本站只提供参考并不构成任何投资及应用建议。本站是信息平台,网站上部分文章为转载,并不用于任何商业目的,我们已经尽可能的对作者和来源进行了通告,但是能力有限或疏忽造成漏登,请及时联系我们,我们将根据著作权人的要求立即更正或者删除有关内容。

GMT+8, 2024-3-29 15:30 , Processed in 0.140382 second(s), 24 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表