最近在项目遇到这样的问题:在一线性垂直布局内,有两个垂直的RecyclerView,如果直接高度直接设置wrap-content,
 通常会导致滑动冲突或是内容显示不全。

首先说下解决的思路,就是在最外面嵌套一层自定义的ScrollView,重写其相关方法,判断若为垂直滑动则拦截下来,不交由RecyclerView来处理。 这样的话,滑动冲突就能解决,并且是很流畅的。

不过这样在有些设备可能还会出现个问题, 就是内容显示不全。这里可以通过在显示不全的RecyclerView外面套一层RelativeLayout,即:


           <RelativeLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    >
                    <!-- 和项目为androidx无关 -->

                    <androidx.recyclerview.widget.RecyclerView
                        android:id="@+id/recyclerview"
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content" />
           </RelativeLayout>


这样的话, 内容就可以显示完全了。

下面继续ScrollView的滑动事件


自定义一个view,并继承自ScrollView, 再重写onInterceptTouchEvent方法;

具体内容则是:


    @Override
    public boolean onInterceptTouchEvent(MotionEvent e) {
        int action = e.getAction();
        switch (action) {
            case MotionEvent.ACTION_DOWN:
                // downX = (int) e.getRawX();
                downY = (int) e.getRawY();
                break;
            case MotionEvent.ACTION_MOVE:
                int moveY = (int) e.getRawY();
                if (Math.abs(moveY - downY) > touchSlop) {
                    return true;
                }
        }
        return super.onInterceptTouchEvent(e);
    }


获取触屏开始和结束位置坐标的Y值,取相减的绝对值,再与touchSlop比较,大于这个值则判断此次为滑动事件,则拦截。 其中touchSlop 是判断是否滑动的参考值。官方给出的解释是

/**
 *  Distance in pixels a touch can wander before we think the user is scrolling
 */

大体过程就是这样,下面贴上自定义ScrollView的全部代码:



package com.asche.wetalk.helper;

import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.ViewConfiguration;
import android.widget.ScrollView;

/**
 *  拦截滑动事件,不由recyclerview处理
 */
public class MyScrollViewScroll extends ScrollView {
    // private int downX;
    private int downY;
    private int touchSlop;

    public MyScrollViewScroll(Context context) {
        super(context);
        touchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
    }

    public MyScrollViewScroll(Context context, AttributeSet attrs) {
        super(context, attrs);
        touchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
    }

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

    @Override
    public boolean onInterceptTouchEvent(MotionEvent e) {
        int action = e.getAction();
        switch (action) {
            case MotionEvent.ACTION_DOWN:
                // downX = (int) e.getRawX();
                downY = (int) e.getRawY();
                break;
            case MotionEvent.ACTION_MOVE:
                int moveY = (int) e.getRawY();
                if (Math.abs(moveY - downY) > touchSlop) {
                    return true;
                }
        }
        return super.onInterceptTouchEvent(e);
    }

    @Override
    protected void onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY) {
        super.onOverScrolled(scrollX, scrollY, clampedX, clampedY);
    }
}