ScrollView嵌套RecyclerView问题:rv_hall_of_fame无法显示全部项求助
我之前也碰到过一模一样的问题,嵌套在ScrollView里的RecyclerView经常会出现高度计算错误,导致部分条目被截断。试过你提到的那些方法没用的话,可以试试下面这几个方案:
方案一:自定义LayoutManager强制测量全高
问题的核心是RecyclerView在ScrollView中时,默认的LayoutManager不会正确计算所有条目的总高度,只会测量当前可见区域。我们可以自定义一个LinearLayoutManager来修复这个问题:
public class FullHeightLinearLayoutManager extends LinearLayoutManager { public FullHeightLinearLayoutManager(Context context) { super(context); } public FullHeightLinearLayoutManager(Context context, int orientation, boolean reverseLayout) { super(context, orientation, reverseLayout); } public FullHeightLinearLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); } @Override public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state, int widthSpec, int heightSpec) { // 强制让LayoutManager测量所有条目的总高度 int heightSpecCustom = View.MeasureSpec.makeMeasureSpec( Integer.MAX_VALUE >> 2, View.MeasureSpec.AT_MOST); super.onMeasure(recycler, state, widthSpec, heightSpecCustom); // 将测量得到的总高度设置给RecyclerView ViewGroup.LayoutParams params = getRecyclerView().getLayoutParams(); params.height = getMeasuredHeight(); } }
然后在代码里给rv_hall_of_fame设置这个自定义LayoutManager,同时保留setNestedScrollingEnabled(false)来避免嵌套滚动冲突:
RecyclerView rvHallOfFame = findViewById(R.id.rv_hall_of_fame); rvHallOfFame.setLayoutManager(new FullHeightLinearLayoutManager(this)); rvHallOfFame.setNestedScrollingEnabled(false);
方案二:重构布局,避免嵌套滚动(推荐)
其实从性能和布局合理性来说,最好的解决方式是去掉外层的ScrollView,让两个RecyclerView各自负责自己的滚动。可以把外层换成LinearLayout,给下面的RecyclerView设置权重占满剩余空间:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/grey_f2"> <android.support.v7.widget.RecyclerView android:id="@+id/rv_achievement_badges" android:layout_width="match_parent" android:layout_height="wrap_content" android:focusableInTouchMode="false" /> <LinearLayout android:background="@color/white" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:orientation="vertical" android:padding="25dp"> <com.sharesmile.share.views.LBTextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/hall_of_fame" android:layout_marginTop="10dp" android:layout_marginBottom="10dp" android:textColor="@color/black_64" android:textSize="20sp" /> <android.support.v7.widget.RecyclerView android:id="@+id/rv_hall_of_fame" android:layout_width="match_parent" android:layout_height="match_parent" android:focusableInTouchMode="false" /> </LinearLayout> </LinearLayout>
这种方式不仅能解决显示不全的问题,还能避免ScrollView嵌套RecyclerView导致的一次性加载所有条目、内存占用过高的问题,性能更优。
额外检查点
最后别忘了检查你的RecyclerView Item布局:确保Item的根布局高度是wrap_content,如果设置成match_parent也会导致测量错误,进而出现显示不全的情况。
如果你的项目已经迁移到AndroidX,记得把布局里的android.support.v7.widget.RecyclerView替换成androidx.recyclerview.widget.RecyclerView,避免兼容问题。
内容的提问来源于stack exchange,提问作者Parth Anjaria

