View事件分发--长按事件、点击事件处理

104 阅读1分钟

如何监听一个View的长按事件

view.setOnLongClickListener(new View.OnLongClickListener() {
    @Override
    public boolean onLongClick(View v) {
            //  TODO
           return false;
    }
});


  • onLongClick 的返回值默认是false,这样写会有什么问题呢。如果这个时候我们同时监听了View的点击事件,触发了长按事件后,点击事件也同样会触发。很显然这不是我们想要的。
  • 如果我们把onLongClick 的返回值设值成true后,长按事件就消费了此次的事件,点击事件就不会触发。
  • 针对上诉问题我们应该怎么处理呢?
  tv.setOnLongClickListener(new View.OnLongClickListener() {
            @Override
            public boolean onLongClick(View v) {
                tv.setTag("longclick");
                copy((TextView) v);
                return true;
            }
        });

 tv.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                if (event.getAction() == MotionEvent.ACTION_UP) {
                    if (parentView!=null && tv.getTag()==null){
                        parentView.performClick();
                    }
                    if (tv.getTag()!=null){
                        tv.setTag(null);
                    }
                }
                return false;
            }
        });       

具体原理我们来简单看一下 View事件分发的源码 ,具体可参考)android 事件分发机制

public boolean onTouchEvent(MotionEvent event) {
        // ...省略
 
        // 重点
        if (clickable || (viewFlags & TOOLTIP) == TOOLTIP) {
            switch (action) {
                case MotionEvent.ACTION_UP:
       // 1.mHasPerformedLongPress跟长按有关,默认为false,
       // 只有 onLongClick回调方法返回true时,该值才为true
                        if (!mHasPerformedLongPress && !mIgnoreNextUpEvent){
                            removeLongPressCallback();
                            if (!focusTaken) {
                            
                                if (mPerformClick == null) {
                                    mPerformClick = new PerformClick();
                                }
 
                                if (!post(mPerformClick)) {
 
                                    performClickInternal();
                                }
                            }
                        }
 
                    break;
            }
 
            return true;
        }
 
        return false;
    }

结论:

  • onLongClick返回值设置成true后,长按事件就不会在onTouchEvent里就不会触发 点击事件(performClickInternal)
  • 把点击事件放在 onTouch里手动触发,并且通过tv的tag屏蔽掉长按事件