android中利用自定义View中的onTouchEvent捕捉长按事件

来源:互联网 发布:易幻网络面试 编辑:程序博客网 时间:2024/06/14 06:58

欲实现的效果是:当手机按住屏幕时,如果在指定的时间内没有移动(如1秒),那么进入长按模式,此时手指在屏幕上移动都算作长按模式。如果手机按住屏幕就立马移动,那么就算作移动模式。


MotionEvent提供了当前的操作类型,按下(ACTION_DOWN)、 移动 (ACTION_MOVE)、弹起 (ACTION_UP)。MotionEvent 类同时提供了记录当前坐标的函数(getRawX(),getRawY())。event.getDownTime()用来记录event发生时的时间,event.getEventTime()用来记录最近一个ACTION_MOVE发生时的时间。


大概思路如下:在按下时记录x,y坐标以及按下时间,当第一次移动的时候获取移动的时间,如果大于指定的长按时间,那么进入长按模式,否则就是普通的移动模式。很容易在模拟器里面实现了这个效果,但是当在真机里面运行时,却无法实现这样的效果。原来模拟器点击的时候能够保证在不移动鼠标的情况下不触发ACTION_MOVE,但是真机却很敏感,几乎在ACTION_DOWN后的几毫秒之后就立马不停的ACTION_MOVE了。想了一下,其实只要稍微变通下变可以在真机上也实现相同的效果了。那就是判断ACTION_MOVE后的坐标和ACTION_DOWN的坐标的偏移值是否小于我们指定的偏移像素,如果在指定值内,那么认为没有移动。

代码如下:

声明一个用来判断是否为长按模式的布尔型变量同时定义所需变量

private Boolean mIsLongPressed = false;private float mLastMotionX = 0;private float mLastMotionY = 0;private long lastDown_Time = 0;


判断是否为长按模式的函数
/**     * * 判断是否有长按动作发生      * @param lastX      *            按下时X坐标      * @param lastY      *            按下时Y坐标      * @param thisX     *            移动时X坐标      * @param thisY     *            移动时Y坐标      * @param lastDownTime     *            按下时间      * @param thisEventTime     *            移动时间      * @param longPressTime     *            判断长按时间的阀值     */    public boolean isLongPressed(float lastX, float lastY, float thisX,                                 float thisY, long lastDownTime, long thisEventTime,                                 long longPressTime) {        float offsetX = Math.abs(thisX - lastX);        float offsetY = Math.abs(thisY - lastY);        long intervalTime = thisEventTime - lastDownTime;        if (offsetX <= 10 && offsetY <= 10 && intervalTime >= longPressTime) {            return true;        }        return false;    }

在ACTION_DOWN中记录按下时的坐标和时间

mLastMotionX = event.getRawX()<span style="font-family: Arial, Helvetica, sans-serif;">;</span>                mLastMotionY = <span style="font-family: Arial, Helvetica, sans-serif;">event.getRaw</span><span style="font-family: Arial, Helvetica, sans-serif;">Y();</span>                lastDown_Time = event.getDownTime();

在ACTION_MOVE中执行如下代码

<pre name="code" class="java">//检测是否长按,在非长按时检测                if (!mIsLongPressed) {                    float mThisMotionX = <span style="font-family: Arial, Helvetica, sans-serif;">event.getRaw</span><span style="font-family: Arial, Helvetica, sans-serif;">X();</span>                    float mThisMotionY = <span style="font-family: Arial, Helvetica, sans-serif;">event.getRaw</span>Y();                    long thisEvent_Time = event.getEventTime();                    ;                    mIsLongPressed = isLongPressed(mLastMotionX, mLastMotionY, mThisMotionX, mThisMotionY, lastDown_Time, thisEvent_Time, 1000);                }                if (mIsLongPressed) {                    //长按模式所做的事                    Log.e("longPress", "longPress");                } else {                    //移动模式所做的事                }

最后别忘了在ACTION_UP中将标志置为false

mIsLongPressed = false;

上述代码存在两个bug:

//1.移动距离很大,触发多次move,会判断为拖动,但是此时长按判断条件的时间长度已经符合1s要求,当你的触摸点移动到刚开始触摸的点附近时就会判定为长按事件,而此时不应为长按//2.move的距离很小,满足长按判定的距离条件,但如果此时不满足时间条件,你的手指触摸在屏幕上不发抖,此时就一直处在move的事件中,时间判定一直不符合条件,就不会触发长按效果,而此时应该为长按
解决方法:

float mThisMoveMotionX = event.getRawX();                float mThisMoveMotionY = event.getRawY();                //检测是否长按,在非长按时检测                if (!mIsLongPressed) {                    long thisEvent_Time = event.getEventTime();//1.移动距离很大,触发多次move,会判断为拖动,但是此时长按判断条件的时间长度已经符合1s要求,当你的触摸点移动到刚开始触摸的点附近时就会判定为长按事件,而此时不应为长按                    //2.move的距离很小,满足长按判定的距离条件,但如果此时不满足时间条件,你的手指触摸在屏幕上不发抖,此时就一直处在move的事件中,时间判定一直不符合条件,就不会触发长按效果,而此时应该为长按                    //mIsLongPressed = isLongPressed(lastDown_Time, thisEvent_Time, 1000);                    mIsLongPressed = isLongPressed(mLastDownMotionX, mLastDownMotionY, mThisMoveMotionX, mThisMoveMotionY, lastDown_Time, thisEvent_Time, 800);                    if (mIsLongPressed) {                        vibrator = (Vibrator) this.getContext().getSystemService(Context.VIBRATOR_SERVICE);                        vibrator.vibrate(50);                    }                }                if (mIsLongPressed) {                        //长按模式所做的事                        Log.e("longPress", "longPress");                        //invalidate();                        //mIsLongPressed = false;                } else {                    //移动模式所做的事                    //每次只要移动的距离大于10,就判定为拖动,一经判定为拖动,将mLastDownMotionX和mLastDownMotionY置为0(屏幕左上角,触摸的几率很小),表示无论再怎么调用move也不会判定为长按事件。                    if(Math.abs(mThisMoveMotionX - mLastDownMotionX) > 10 && Math.abs(mThisMoveMotionY - mLastDownMotionY) > 10) {                        mLastDownMotionX = 0;                        mLastDownMotionY = 0;                    }}

de

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 用电焊后眼睛痛怎么办 看电焊后眼睛痛怎么办 眼睛焊电焊很痛怎么办 电焊没带眼睛痛怎么办 有东西进眼睛了怎么办 眼睛有东西磨眼怎么办 怀孕了眼睛肿疼怎么办 眼睛疼又红血丝怎么办 用眼过度眼睛疼怎么办 眼睛玩手机视力下降怎么办 看手机眼睛疼该怎么办 眼睛眨一下就痛怎么办 着火了怎么办教案详案 汽车尾灯磕破了怎么办 后尾灯灯罩裂了怎么办 七氟丙烷喷伤了怎么办 冒险岛2fps低怎么办 虐杀原形2很卡怎么办 玩虐杀原形2卡怎么办 虐杀原形2闪退怎么办 电脑显示不出u盘怎么办 电脑不显示u盘怎么办 u盘在电脑不显示怎么办 笔记本不识别u盘怎么办 u盘突然识别不了怎么办 xp电脑读不出u盘怎么办 电脑无法读取u盘怎么办 win7电脑不读u盘怎么办 电脑识别不出u盘怎么办 u盘电脑读不出来怎么办 u盘突然无法识别怎么办 u盘电脑无法识别怎么办 系统无法识别u盘怎么办 手机u盘无法识别怎么办 u盘无法被识别怎么办 电脑不能读取u盘怎么办 电脑装系统卡了怎么办 怀孕三个月胚胎停育怎么办 被蟑螂咬了怎么办图片 有家人进了传销怎么办 有亲人进了传销怎么办