Android 解决Touch事件传递不连贯的问题

在事件分发的过程中,用于Android特有的事件分发机制,可能出现两个问题:

  1. 子View在滑动过程中产生requestDisallowTouchEvent()导致父View没有办法拦截到事件的问题(父View没有回调onInterceptTouchEvent())。

  2. 父View拦截事件并消耗,此时达到某个临界值,父View不再需要事件,但是子View无法从ACTION_MOVE事件直接开始处理,所以导致子View只能从下次事件序列开始处理。

问题一解决

我们只需重写在父ViewGroup重写requestDisallowTouchEvent(),不调用super的同名方法,因为super会在此ViewGroup放上标记,导致子ViewGroup没法办法继续拦截事件

 @Override
public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
    //super.requestDisallowInterceptTouchEvent(disallowIntercept);
    // 但是需要继续向上传递,否则ListView之类的控件很多状态会错误
    getParent().requestDisallowInterceptTouchEvent(disallowIntercept);
}

问题二解决

我们在当前ViewGroup中处理Touch事件达到临界值时,自行补发ACTION_UP和ACTION_DOWN事件,让事件传递流程重启,这样就不会出现子View需要在下次事件序列才能重启的问题了。

// ViewGroup拦截到事件后进行处理
@Override
public boolean onTouchEvent(MotionEvent event) {
    Log.d(TAG, "onTouchEvent: " + event);
    final int action = event.getAction();
    boolean needReset = false;
    switch (action) {
        case MotionEvent.ACTION_DOWN:
            break;
        case MotionEvent.ACTION_MOVE:
            int offset = (int) (event.getY() - mLastY);
            // 此时滑动到顶部,需要重新启动事件传递机制
            if (mChild.getTop() + offset < mHoverY) {
                offset = (int) (mHoverY - mChild.getTop());
                needReset = true;
            }
            mChild.offsetTopAndBottom(offset);
            if (needReset) {
                // 重启ListView的事件机制
                resetTouchEvent(event);
            }
            break;
    }
    mLastY = event.getY();
    return super.onTouchEvent(event);
}

// 使子View恢复事件
private void resetTouchEvent(MotionEvent event) {
    MotionEvent ev = MotionEvent.obtain(event);
    ev.setAction(MotionEvent.ACTION_UP);
    MotionEvent ev2 = MotionEvent.obtain(event);
    ev.setAction(MotionEvent.ACTION_CANCEL);
    MotionEvent ev3 = MotionEvent.obtain(event);
    ev3.setAction(MotionEvent.ACTION_DOWN);
    dispatchTouchEvent(ev);
    dispatchTouchEvent(ev2);
    dispatchTouchEvent(ev3);
    ev.recycle();
    ev2.recycle();
    ev3.recycle();
}

当然也可是使用NestScroll机制进行解决,NestScroll机制没有上述的两种问题。

解决两个问题后,可以较为流畅的处理手势。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值