关于listview重写onintercepttouchevent不响应move和up事件

来源:互联网 发布:网络营销推广软件 编辑:程序博客网 时间:2024/06/03 14:42

首先来讲讲viewgroup的事件分发机制(盗来的图):


首先执行diapatchtouch,在diapatchtouch中调用onintercepttouchevent,在其中判断有没有拦截,如果拦截了就不调用子view的diapatchtouch,调用自身的touch事件,如果不拦截就调用子view 的diapatchtouch,执行view的事件分发机制。

这里也再说说view的分发机制好了:首先必定的dispatchTouch

public boolean dispatchTouchEvent(MotionEvent event) {    if (mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED &&            mOnTouchListener.onTouch(this, event)) {        return true;    }    return onTouchEvent(event);}
mOnTouchListener就是我们setontouchlistner时候赋的值,这个值只要我们set了就不会空,第二个判断是是否可点击,最后一个就是我们在setontouchlistener中重写的那个touch方法,在这里如果我们的touch返回false的会就继续调用ontouchevent方法,在其中会调用onclick方法。还有一个要注意的地方,当dispatchTouchEvent在进行事件分发的时候,只有前一个action返回true,才会触发后一个action


listview也是viewgroup,所以讲了上面的分发机制有助于我们分析我们的问题:重写listview中的onintercepttouchevent的时候竟然没有响应move和up事件,也就是一个viewgroup的onintercepttouchevent的move和up没有调用,看看上面的图,我们就知道是在dispatchtouch调用的onintercepttouchevent,那就去看下listview的dispatchtouch的方法中到底做了什么手脚。一进去看发现listview中没有重写这个方法,他的父类(AbsListView)中也没有,一直往上跟,只到viewgroup才有这个方法:

public boolean dispatchTouchEvent(MotionEvent ev) {    final int action = ev.getAction();    final float xf = ev.getX();    final float yf = ev.getY();    final float scrolledXFloat = xf + mScrollX;    final float scrolledYFloat = yf + mScrollY;    final Rect frame = mTempRect;    boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;    if (action == MotionEvent.ACTION_DOWN) {        if (mMotionTarget != null) {            mMotionTarget = null;        }        if (disallowIntercept || !onInterceptTouchEvent(ev)) {            ev.setAction(MotionEvent.ACTION_DOWN);            final int scrolledXInt = (int) scrolledXFloat;            final int scrolledYInt = (int) scrolledYFloat;            final View[] children = mChildren;            final int count = mChildrenCount;            for (int i = count - 1; i >= 0; i--) {                final View child = children[i];                if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE                        || child.getAnimation() != null) {                    child.getHitRect(frame);                    if (frame.contains(scrolledXInt, scrolledYInt)) {                        final float xc = scrolledXFloat - child.mLeft;                        final float yc = scrolledYFloat - child.mTop;                        ev.setLocation(xc, yc);                        child.mPrivateFlags &= ~CANCEL_NEXT_UP_EVENT;                        if (child.dispatchTouchEvent(ev))  {                            mMotionTarget = child;                            return true;                        }                    }                }            }        }    }    boolean isUpOrCancel = (action == MotionEvent.ACTION_UP) ||            (action == MotionEvent.ACTION_CANCEL);    if (isUpOrCancel) {        mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT;    }    final View target = mMotionTarget;    if (target == null) {        ev.setLocation(xf, yf);        if ((mPrivateFlags & CANCEL_NEXT_UP_EVENT) != 0) {            ev.setAction(MotionEvent.ACTION_CANCEL);            mPrivateFlags &= ~CANCEL_NEXT_UP_EVENT;        }        return super.dispatchTouchEvent(ev);    }    if (!disallowIntercept && onInterceptTouchEvent(ev)) {        final float xc = scrolledXFloat - (float) target.mLeft;        final float yc = scrolledYFloat - (float) target.mTop;        mPrivateFlags &= ~CANCEL_NEXT_UP_EVENT;        ev.setAction(MotionEvent.ACTION_CANCEL);        ev.setLocation(xc, yc);        if (!target.dispatchTouchEvent(ev)) {        }        mMotionTarget = null;        return true;    }    if (isUpOrCancel) {        mMotionTarget = null;    }    final float xc = scrolledXFloat - (float) target.mLeft;    final float yc = scrolledYFloat - (float) target.mTop;    ev.setLocation(xc, yc);    if ((target.mPrivateFlags & CANCEL_NEXT_UP_EVENT) != 0) {        ev.setAction(MotionEvent.ACTION_CANCEL);        target.mPrivateFlags &= ~CANCEL_NEXT_UP_EVENT;        mMotionTarget = null;    }    return target.dispatchTouchEvent(ev);}

上面就是源码(不同的版本会有差异),可以看到两个地方调用了onintercepttouchevent,而

final View target = mMotionTarget;

这句一般都是target = null,所以就是直接执行super.dispatchtouch,也就相当于执行一个view的dispatchtouch,直接就和touch、touchevent相关了,不再纠缠onintercepttouchevent,onintercepttouchevent也就不被调用了。说到这里我又去继承LinearLayout写了一个自定义的线性布局,然后重写了其中的dispatchtouch、onintercepttouchevent、ontouchEvent方法,然后惊奇的发现,连dispatchEvent都只响应down了,然后我不然ontouchevent返回super.ontouchevent,而是直接返回true(之前说了,返回true可以响应下一个action,false就是不响应),达到了和listview一样的效果。


说到这里就可以做一个总结了:对于所有的viewgroup,down了之后首先进入的就是dispatchtouch,随后判断是否拦截,不拦截分发给子view,拦截执行自己的ontouchevent方法,一般都是不拦截,然后发给子view,这个时候也会有差异,如果子view是可点击的,那么执行子view的dispatch和ontouchevent,否则的话还是会执行viewgroup的ontouchevent,紧接着move事件,很多viewgroup就直接不响应了(直接在down的dis中就返回了false,前提是子view不可点击),up和move差不多,都是根据子view来决定响不响应,更精确的说是子view的dispatchtouch方法的返回值。

差不多事件分发就这些内容,讲的很乱,大家自己自慢慢体会,有空我会整理出更好的文章。


大家可以自己去试验看看:重写dispatchtouch,直接返回true或者false(不调用supr.dspatchtouch)都不会再调用onintercepttouchevent和ontouchevent响应其中的任何事件

0 0
原创粉丝点击