安卓多個RecyclerView滑動與顯示問題
最近在專案遇到這樣的問題:在一線性垂直佈局內,有兩個垂直的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); } }