为了账号安全,请及时绑定邮箱和手机立即绑定

魅族手机onTouchEvent 、onLongClick踩坑

标签:
Android

在遇到的坑之前我们先了解 Android onTouchEvent, onClick及onLongClick的调用机制
1.  onTouchEvent:

 onTouchEvent中要处理的最常用的3个事件就是:ACTION_DOWN(按下)、ACTION_MOVE(移动)、ACTION_UP(抬起)。

2.  onClick、onLongClick与onTouchEvent

    
 在Android中,onClick、onLongClick的触发是和ACTION_DOWN及ACTION_UP相关的,在时序上,如果我们在一个View中同时覆写了onClick、onLongClick及onTouchEvent的话,onTouchEvent是最先捕捉到ACTION_DOWN和ACTION_UP事件的,其次才可能触发onClick或者onLongClick。主要的逻辑在View.java中的onTouchEvent方法中实现的,主要的操作是在View.onTucchEvent下的:       switch (event.getAction()) {            case MotionEvent.ACTION_UP:                boolean prepressed = (mPrivateFlags & PFLAG_PREPRESSED) != 0;                if ((mPrivateFlags & PFLAG_PRESSED) != 0 || prepressed) {                    // take focus if we don't have it already and we should in
                    // touch mode.
                    boolean focusTaken = false;                    if (isFocusable() && isFocusableInTouchMode() && !isFocused()) {
                        focusTaken = requestFocus();
                    }                    if (prepressed) {                        // The button is being released before we actually
                        // showed it as pressed.  Make it show the pressed
                        // state now (before scheduling the click) to ensure
                        // the user sees it.
                        setPressed(true, x, y);
                   }                    if (!mHasPerformedLongPress) {                        // This is a tap, so remove the longpress check
                        removeLongPressCallback();                        // Only perform take click actions if we were in the pressed state
                        if (!focusTaken) {                            // Use a Runnable and post this rather than calling
                            // performClick directly. This lets other visual state
                            // of the view update before click actions start.
                            if (mPerformClick == null) {
                                mPerformClick = new PerformClick();
                            }                            if (!post(mPerformClick)) {
                                performClick();
                            }
                        }
                    }                    if (mUnsetPressedState == null) {
                        mUnsetPressedState = new UnsetPressedState();
                    }                    if (prepressed) {
                        postDelayed(mUnsetPressedState,
                                ViewConfiguration.getPressedStateDuration());
                    } else if (!post(mUnsetPressedState)) {                        // If the post failed, unpress right now
                        mUnsetPressedState.run();
                    }

                    removeTapCallback();
                }                break;            case MotionEvent.ACTION_DOWN:
                mHasPerformedLongPress = false;                if (performButtonActionOnTouchDown(event)) {                    break;
                }                // Walk up the hierarchy to determine if we're inside a scrolling container.
                boolean isInScrollingContainer = isInScrollingContainer();                // For views inside a scrolling container, delay the pressed feedback for
                // a short period in case this is a scroll.
                if (isInScrollingContainer) {
                    mPrivateFlags |= PFLAG_PREPRESSED;                    if (mPendingCheckForTap == null) {
                        mPendingCheckForTap = new CheckForTap();
                    }
                    mPendingCheckForTap.x = event.getX();
                    mPendingCheckForTap.y = event.getY();
                    postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout());
                } else {                    // Not inside a scrolling container, so show the feedback right away
                    setPressed(true, x, y);
                    checkForLongClick(0);
                }                break;            case MotionEvent.ACTION_CANCEL:
                setPressed(false);
                removeTapCallback();
                removeLongPressCallback();                break;            case MotionEvent.ACTION_MOVE:
                drawableHotspotChanged(x, y);                // Be lenient about moving outside of buttons
                if (!pointInView(x, y, mTouchSlop)) {                    // Outside button
                    removeTapCallback();                    if ((mPrivateFlags & PFLAG_PRESSED) != 0) {                        // Remove any future long press/tap checks
                        removeLongPressCallback();

                        setPressed(false);
                    }
                }                break;

可以看到,Click的触发是在系统捕捉到ACTION_UP后发生并由performClick()执行的;LongClick的触发则是从ACTION_DOWN开始,由checkForLongClick()方法完成的;
他们执行Touch事件的的顺序 ACTION_DOWN ->  ACTION_UP  ->  OnClick/OnLongClick。 

首先,该View会先响应ACTION_DOWN事件,并返回一个boolean值,这里有两种判断:
1. 返回true,表示该View接受此按下动作,就是说这个点击动作的按下操作被中止,然后就是响应ACTION_UP事件。点击动作的按下操作被ACTION_DOWN接受之后就结束了,所以之后的OnClick/OnLongClick事件就不会响应了。

  1. 返回false,表示该View不接受此按下动作,响应完之后,按下操作继续往下发,之后是响应ACTION_UP事件,这里又有一个判断:

     如果ACTION_UP事件返回true,表示ACTION_UP接受松开操作,松开操作中止;View会一直处于按下状态,之后View便会响应OnLongClick事件。
    
    如果ACTION_UP事件返回false,表示ACTION_UP不接收松开操作,松开操作继续下发;因为按下与松开操作都没有被中止,所以之后View就会响应OnClick事件。

下面就是我在魅族中踩的坑了:

手机在EditText长按进行粘贴,会触发OnLongClick 的事件,但是我在魅族的手机EditText长按进行粘贴,如果做了onTouchEvent监听,死活的都不会触发OnLongClick 的事件,不够onTouchEvent返回的是true还是false 都白费,当然也不会进行粘贴;其他的手机都是按照正常的节奏来,就只有魅族!
找到问题了现在就是怎么去解决问题,这里我用到onTouchEvent 主要监听的是ACTION_MOVE 的处理,既然onTuchEvent不行就只有用其方式来监听滑动了,用到的是GestureDetector.SimpleOnGestureListener 进行监听的 :

public static class SimpleOnGestureListener implements OnGestureListener, OnDoubleTapListener {  
 // --------------OnGestureListener的接口有这几个----------------
 // 抬起,手指离开触摸屏时触发(长按、滚动、滑动时,不会触发这个手势)  
    public boolean onSingleTapUp(MotionEvent e) {        return false;
    }   // 长按,触摸屏按下后既不抬起也不移动,过一段时间后触发 
    public void onLongPress(MotionEvent e) {
    }  // 滚动,触摸屏按下后移动  
    public boolean onScroll(MotionEvent e1, MotionEvent e2,            float distanceX, float distanceY) {        return false;
    }  // 滑动,触摸屏按下后快速移动并抬起,会先触发滚动手势,跟着触发一个滑动手势  
    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,            float velocityY) {        return false;
    }  // 短按,触摸屏按下后片刻后抬起,会触发这个手势,如果迅速抬起则不会 
    public void onShowPress(MotionEvent e) {
    }    // 单击,触摸屏按下时立刻触发
    public boolean onDown(MotionEvent e) {        return false;
    }    //------------------------OnDoubleTapListener的接口有这几个-----------
  // 双击,手指在触摸屏上迅速点击第二下时触发  
    public boolean onDoubleTap(MotionEvent e) {        return false;
    }   // 双击的按下跟抬起各触发一次  
    public boolean onDoubleTapEvent(MotionEvent e) {        return false;
    }   // 单击确认,即很快的按下并抬起,但并不连续点击第二下  
    public boolean onSingleTapConfirmed(MotionEvent e) {        return false;
    }
}

于是我重写我的EditText 继承EditText:

public class MyEditText extends EditText {private GestureDetector mGestureDetector;private SimpleOnGestureListener simpleOnGestureListener;private Context context;public MyEditText(Context context) {    super(context);    this.context = context;
    setLongClickable(true);
}public void setMyGestureListener(SimpleOnGestureListener simpleOnGestureListener) {    this.simpleOnGestureListener = simpleOnGestureListener;
    setGestureDetector();
}public MyEditText(Context context, AttributeSet attrs) {    super(context, attrs);
    setLongClickable(true);    this.context = context;

}private void setGestureDetector() {
    mGestureDetector = new GestureDetector(context, simpleOnGestureListener);    this.setOnTouchListener(new OnTouchListener() {        public boolean onTouch(View v, MotionEvent event) {            return mGestureDetector.onTouchEvent(event);
        }
    });
}

}
注意:

 1.这里一定要记得设置longClickable为true, 否则手势识别无法正确工作,只会返回Down, Show, Long三种手势 2. 必须在View的onTouchListener中调用手势识别,而不能像Activity一样重载onTouchEvent,否则同样手势识别无法正确工作

最后这样就ok了:

        mTvEditContent.setMyGestureListener(new SimpleOnGestureListener() {        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {            // 处理我想做的
            return super.onScroll(e1, e2, distanceX, distanceY);
        }
    });


原文链接:http://www.apkbus.com/blog-87624-76395.html

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消