scrollview嵌套recycleview后,点击item事件失效

当ScrollView内嵌套RecyclerView并重写onInterceptTouchEvent()以避免冲突时,遇到在高分辨率设备上RecyclerView item点击事件失效的问题。原因是ACTION_MOVE事件被拦截,导致事件无法传递到item。解决方法是调整x和y方向的判断阈值,允许部分ACTION_MOVE事件通过,以确保点击功能正常。
摘要由CSDN通过智能技术生成

起因:项目需要,布局放置了纵向滑动的scrollview和横向滑动的recycleview,之后为了避免横向滑动时触发纵向移动,重写了两个控件的onInterceptTouchEvent()方法。如下:

 

public class JudgeNestedScrollView extends NestedScrollView {
    private boolean isNeedScroll = true;
    private float xDistance, yDistance, xLast, yLast;
    private int scaledTouchSlop;

    public JudgeNestedScrollView(Context context) {
        super(context, null);
    }

    public JudgeNestedScrollView(Context context, AttributeSet attrs) {
        super(context, attrs, 0);
    }

    public JudgeNestedScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        scaledTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                xDistance = yDistance = 0f;
                xLast = ev.getX();
                yLast = ev.getY();
                break;
            case MotionEvent.ACTION_MOVE:
                final float curX = ev.getX();
                final float curY = ev.getY();

                xDistance += Math.abs(curX - xLast);
                yDistance += Math.abs(curY - yLast);
                xLast = curX;
                yLast = curY;
                //横向移动大于纵向时,不会拦截该事件
                return !(xDistance >= yDistance || yDistance < scaledTouchSlop) && isNeedScroll;
        }
        return super.onInterceptTouchEvent(ev);
    }

    /*
    该方法用来处理NestedScrollView是否拦截滑动事件
     */
    public void setNeedScroll(boolean isNeedScroll) {
        this.isNeedScroll = isNeedScroll;
    }
}

 

public class ScrollRecycleView extends RecyclerView {
  
    private float lastX, lastY;

    @Override
    public boolean onInterceptTouchEvent(MotionEvent e) {

        boolean intercept = super.onInterceptTouchEvent(e);

        switch (e.getAction()) {

            case MotionEvent.ACTION_DOWN:
                lastX = e.getX();
                lastY = e.getY();
                break;
            case MotionEvent.ACTION_MOVE:
                // 只要横向大于竖向,就拦截掉事件
                float slopX = Math.abs(e.getX() - lastX);
                float slopY = Math.abs(e.getY() - lastY);
                if((slopX > 0 || slopY > 0) && slopX >= slopY){
                    requestDisallowInterceptTouchEvent(true);
                    intercept = true;
                }
                break;
            case MotionEvent.ACTION_UP:
                intercept = false;
                break;
        }
        return intercept;
    }

 

然后,在较低分辨率的屏幕上测试,一切安好。换了一个高分辨率的手机(三星galaxy S10)就发生了如标题所说的事情,item点击失效了。在进行了若干调试之后发现,在高分辨率的屏幕上点击item很大概率会触发MotionEvent.ACTION_MOVE事件,由于该事件横向和纵向滑动都已经被拦截,使得事件无法到达item导致点击失效。

解决方法:修改了x和y方向判断值,在一定取值范围内不去拦截事件

 

@Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                xDistance = yDistance = 0f;
                xLast = ev.getX();
                yLast = ev.getY();
                break;
            case MotionEvent.ACTION_MOVE:
                final float curX = ev.getX();
                final float curY = ev.getY();

                xDistance += Math.abs(curX - xLast);
                yDistance += Math.abs(curY - yLast);
                xLast = curX;
                yLast = curY;
                Log.e("SiberiaDante", "xDistance :" + xDistance + "---yDistance:" + yDistance);
                return !(((xDistance >= yDistance) || yDistance < scaledTouchSlop) || (xDistance < 10 && yDistance < 10)) && isNeedScroll;
        }
        return super.onInterceptTouchEvent(ev);
    }
@Override
public boolean onInterceptTouchEvent(MotionEvent e) {

    boolean intercept = super.onInterceptTouchEvent(e);

    switch (e.getAction()) {

        case MotionEvent.ACTION_DOWN:
            lastX = e.getX();
            lastY = e.getY();
            break;
        case MotionEvent.ACTION_MOVE:
            // 只要横向大于竖向,就拦截掉事件。
            float slopX = Math.abs(e.getX() - lastX);
            float slopY = Math.abs(e.getY() - lastY);
            if((slopX > 5 || slopY > 5) && slopX >= slopY){
                requestDisallowInterceptTouchEvent(true);
                intercept = true;
            }
            break;
        case MotionEvent.ACTION_UP:
            intercept = false;
            break;
    }
    return intercept;
}

 

PS:也许有更好的解决方式,将来发现再来更新

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值