最近在項目遇到這樣的問題:在一線性垂直布局內,有兩個垂直的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);
}
}