如何在NestedScrollView中实现RecyclerView的无限滚动?
解决NestedScrollView嵌套RecyclerView时的视图回收问题
我最近碰到个头疼的问题:单屏里塞了两个RecyclerView,条目太多导致屏幕装不下,于是把RecyclerView放到NestedScrollView里想实现滚动。结果倒好,RecyclerView直接一次性加载所有条目,完全不做视图回收,性能拉胯得不行。
我试过两种方法都没效果:一是给RecyclerView加app:layout_behavior="@string/appbar_scrolling_view_behavior",二是调用mRecyclerView.setNestedScrollingEnabled(false),都没解决问题。有没有靠谱的解决方案?
我的代码
Java代码
myDataset = new ArrayList<>(); mRecyclerView = (RecyclerView) rootView.findViewById(R.id.map_recycler_view); LinearLayoutManager mLayoutManager = new LinearLayoutManager(mcontext); mLayoutManager.setAutoMeasureEnabled(true); mRecyclerView.setLayoutManager(mLayoutManager); mAdapter = new MyAdapter(this); mAdapter.setLinearLayoutManager(mLayoutManager); mAdapter.setRecyclerView(mRecyclerView); mRecyclerView.setAdapter(mAdapter);
XML代码
<android.support.v4.widget.NestedScrollView android:id="@+id/nestedScrollView" android:layout_width="match_parent" android:layout_height="wrap_content"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <FrameLayout android:layout_width="match_parent" android:layout_height="180dp"> <fragment android:id="@+id/googleMap" android:name="com.google.android.gms.maps.SupportMapFragment" android:layout_width="match_parent" android:layout_height="match_parent"/> </FrameLayout> <!-- 第一个RecyclerView --> <android.support.v7.widget.RecyclerView android:id="@+id/map_recycler_view" android:layout_width="match_parent" android:layout_height="wrap_content"/> <!-- 第二个RecyclerView --> <android.support.v7.widget.RecyclerView android:layout_width="match_parent" android:layout_height="wrap_content"/> </LinearLayout> </android.support.v4.widget.NestedScrollView>
可行解决方案
方案一:自定义LinearLayoutManager重写测量逻辑
NestedScrollView会让RecyclerView的高度被强制测量为wrap_content,导致它加载所有子项。我们可以重写LinearLayoutManager的测量方法,让它只计算可见区域的高度:
public class CustomLinearLayoutManager extends LinearLayoutManager { public CustomLinearLayoutManager(Context context) { super(context); } public CustomLinearLayoutManager(Context context, int orientation, boolean reverseLayout) { super(context, orientation, reverseLayout); } public CustomLinearLayoutManager(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) { // 自定义高度测量规则,让RecyclerView只测量可见条目 int heightSpecCustom = View.MeasureSpec.makeMeasureSpec( Integer.MAX_VALUE >> 2, View.MeasureSpec.AT_MOST); super.onMeasure(recycler, state, widthSpec, heightSpecCustom); ViewGroup.LayoutParams params = recyclerView.getLayoutParams(); params.height = getMeasuredHeight(); } }
然后替换原来的LinearLayoutManager:
CustomLinearLayoutManager mLayoutManager = new CustomLinearLayoutManager(mcontext); mRecyclerView.setLayoutManager(mLayoutManager); // 同时关闭RecyclerView自身的嵌套滚动 mRecyclerView.setNestedScrollingEnabled(false);
方案二:用ConstraintLayout替代NestedScrollView(推荐)
如果你的布局支持,直接用ConstraintLayout来布局两个RecyclerView,让它们各自占据剩余空间,完全不需要嵌套滚动,性能更好:
<androidx.constraintlayout.widget.ConstraintLayout android:layout_width="match_parent" android:layout_height="match_parent"> <FrameLayout android:id="@+id/map_container" android:layout_width="match_parent" android:layout_height="180dp" app:layout_constraintTop_toTopOf="parent"/> <androidx.recyclerview.widget.RecyclerView android:id="@+id/first_recycler" android:layout_width="match_parent" android:layout_height="0dp" app:layout_constraintTop_toBottomOf="@id/map_container" app:layout_constraintBottom_toTopOf="@id/second_recycler"/> <androidx.recyclerview.widget.RecyclerView android:id="@+id/second_recycler" android:layout_width="match_parent" android:layout_height="0dp" app:layout_constraintTop_toBottomOf="@id/first_recycler" app:layout_constraintBottom_toBottomOf="parent"/> </androidx.constraintlayout.widget.ConstraintLayout>
这种方式下两个RecyclerView各自独立处理滚动和视图回收,不会出现一次性加载所有条目的问题。
内容的提问来源于stack exchange,提问作者Jshin
相关产品推荐
相关产品推荐

