嵌套 RecyclerView 滚动问题
Posted
技术标签:
【中文标题】嵌套 RecyclerView 滚动问题【英文标题】:Nested RecyclerView scrolling issue 【发布时间】:2018-09-14 01:48:20 【问题描述】:在我的应用程序中,我有垂直父级RecyclerView
,其ViewHolders
内有几个水平子级。但是我有一个非常烦人的滚动问题 - 在我垂直滚动父 RV 后,我想滚动我的一个子 RV,但父级只是拦截所有运动事件,直到我将手指从屏幕上移开然后放回去。这是这种烦人行为的示例。
https://i.imgur.com/dPtmAXD.gif
我尝试了这个问题的所有解决方案 - Nested RecyclerView. How to prevent parent RecyclerView from getting scrolled while child RecyclerView is scrolling?
没有什么对我有用。
看起来 Google Play Market 具有相同的 RV 层次结构,但 ofc 滚动非常好。我尝试实施一些其他主题的解决方案,但没有达到预期效果。
我不知道我应该发布什么代码,但这是我的 Parent RV 的 ViewHolder 示例,其中包含嵌套 RV。
private class UserEventsViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener
private RecyclerView rvUserEvents;
private HomeUserEventsRVAdapter rvAdapter;
public UserEventsViewHolder(View v)
super(v);
rvUserEvents = v.findViewById(R.id.rv_user_events);
rvUserEvents.setLayoutManager(new LinearLayoutManager(itemView.getContext(), LinearLayoutManager.HORIZONTAL, false));
rvUserEvents.setNestedScrollingEnabled(false);
rvUserEvents.setRecycledViewPool(viewPool);
rvAdapter = new HomeUserEventsRVAdapter(presenter);
rvUserEvents.setAdapter(rvAdapter);
v.findViewById(R.id.btn_all_user_events).setOnClickListener(this);
private void bind(UserItemViewModel userItem)
rvAdapter.updateAdapter(userItem);
@Override
public void onClick(View v)
switch (v.getId())
case R.id.btn_all_user_events:
presenter.openUserEventsList();
break;
编辑:我的活动的 XML 代码
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/cl_root"
android:layout_
android:layout_
android:background="@android:color/white">
<android.support.design.widget.AppBarLayout
android:id="@+id/ab_layout"
android:layout_
android:layout_
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
android:fitsSystemWindows="true">
<android.support.design.widget.CollapsingToolbarLayout
android:id="@+id/collapsing_toolbar"
android:layout_
android:layout_
app:layout_scrollFlags="scroll|exitUntilCollapsed"
android:fitsSystemWindows="true"
app:contentScrim="@android:color/white"
app:expandedTitleMarginStart="48dp"
app:expandedTitleMarginEnd="64dp">
<ImageView
android:id="@+id/iv_pic"
android:layout_
android:layout_
android:scaleType="centerCrop"
android:src="@drawable/ic_home_screen_background"
android:fitsSystemWindows="true"
app:layout_collapseMode="parallax"
app:layout_collapseParallaxMultiplier="0.5"/>
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_
android:layout_
android:elevation="7dp"
android:theme="@style/ToolbarTheme"
app:layout_collapseMode="pin"/>
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<android.support.v4.widget.SwipeRefreshLayout
android:id="@+id/sr_layout"
android:layout_
android:layout_
android:layout_marginTop="-6dp"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<android.support.v7.widget.RecyclerView
android:id="@+id/rv_results"
android:clipToPadding="false"
android:scrollbars="vertical"
android:scrollbarThumbVertical="@color/orange_juice_80"
android:scrollbarSize="2dp"
android:layout_
android:layout_
android:background="@drawable/shape_rounded_top_grey"
android:fitsSystemWindows="true" />
</android.support.v4.widget.SwipeRefreshLayout>
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab_add"
android:layout_
android:layout_
android:layout_marginEnd="15dp"
app:backgroundTint="@color/dark_background"
app:layout_anchor="@id/rv_results"
app:layout_anchorGravity="top|right|end"
app:layout_scrollFlags="scroll|exitUntilCollapsed"
app:srcCompat="@drawable/ic_vector_plus_white" />
【问题讨论】:
您的 GIF 链接已过期。我的 Play 商店展示了您在应用中看到的行为。具体来说,您在 Play 商店应用中看到了哪些替代行为? 在 Play 商店应用中,您可以快速滚动父 RV,然后在父仍在滚动时将手指放在其中一个子上 - 此操作会停止父垂直滚动,现在您可以立即滚动子.正如我所说,在我的应用程序中,如果我快速滚动父级垂直 RV,我必须将手指放在屏幕上一次以停止父级滚动,然后我必须将手指从屏幕上移开并将其放回滚动子级。如果我第一次接触孩子,父母会拦截滑动。 @Cheticamp 更新了 gif 链接@Cheticamp 有什么进展吗?有什么解决办法吗?我也有同样的问题。 据我了解,您需要在MotionEvent
s 在RecyclerView
s 之间传递。如果你能提供一个最低限度的可验证示例,我可能会研究一个解决方案。
【参考方案1】:
你在这一行禁用了 RecyclerView 的嵌套滚动
rvUserEvents.setNestedScrollingEnabled(false);
您需要将此行替换为以下内容才能正常滚动
ViewCompat.setNestedScrollingEnabled(rvUserEvents,true);
【讨论】:
好吧,我这样做是因为我在父 RV 中使用 collapsingToolbarLayout。如果我删除此行 collapsingToolbarLayout 将永远不会再次折叠。 我试过你的解决方案 - 不起作用,同样的行为。【参考方案2】:<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_
android:descendantFocusability="blocksDescendants"
android:layout_
android:scrollbars="none" />
在嵌套的 recyclerview 中使用 android:descendantFocusability="blocksDescendants"
属性
【讨论】:
【参考方案3】:嵌套RecyclerView的问题是没有正确检测到正确的手指投掷斜率。
这是一段实际计算正确斜率的代码sn-p https://github.com/minarja1/NestedRecyclerSample/blob/developv2/app/src/main/java/com/example/nestedrecyclersample/utils/ViewExtensions.kt
将类添加到代码库后,您可以使用 Kotlin 扩展调用该函数。
fun RecyclerView.enforceSingleScrollDirection()
val enforcer = SingleScrollDirectionEnforcer()
addOnItemTouchListener(enforcer)
addOnScrollListener(enforcer)
【讨论】:
【参考方案4】: recyclerView.setNestedScrollingEnabled(false);
【讨论】:
以上是关于嵌套 RecyclerView 滚动问题的主要内容,如果未能解决你的问题,请参考以下文章
RecyclerView常见问题解决方案,RecyclerView嵌套自动滚动,RecyclerView 高度设置wrap_content 无作用等问题
RecyclerView常见问题解决方案,RecyclerView嵌套自动滚动,RecyclerView 高度设置wrap_content 无作用等问题
嵌套在 BottomSheet 中的 RecyclerView(水平)防止垂直滚动