【问题标题】:Recycler View Inside Recycler View not Scrolling回收站视图内部回收站视图不滚动
【发布时间】:2016-09-22 06:26:39
【问题描述】:

在另一个 Recycler View 中有一个 Recycler View。两者都需要垂直滚动。外部回收器视图正确滚动,但内部回收器视图没有。

代码如下:

LinearLayoutManager mLayoutManager = new LinearLayoutManager(ViewActivity.this);
outerRecyclerView.setLayoutManager(mLayoutManager);
ViewAdapter adapter = new ViewAdapter(ViewActivity.this);
outerRecyclerView.setAdapter(adapter);

ViewAdapter如下:

public void onBindViewHolder(ViewAdapter.ViewViewHolder holder, int position)
{
  //RECYCLER VIEW
  //TODO: Inner Recycler view scroll movement
  LinearLayoutManager mLayoutManager = new LinearLayoutManager(context);
  holder.protocolRecyclerView.setLayoutManager(mLayoutManager);
  ViewProtocolAdapter adapter = new ViewProtocolAdapter(context);
  holder.protocolRecyclerView.setAdapter(adapter);
}

我在两个回收站视图上都尝试了以下方法,但无法解决问题

recyclerView.addOnItemTouchListener(new RecyclerView.OnItemTouchListener() {
       @Override
       public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
           if(rv.getChildCount() > 0) {
               View childView = rv.findChildViewUnder(e.getX(), e.getY());
               if(childView ==listView) {
                   int action = e.getAction();
                   switch (action) {
                       case MotionEvent.ACTION_DOWN:
                           rv.requestDisallowInterceptTouchEvent(true);
                   }
               }
           }

           return false;
       }

       @Override
       public void onTouchEvent(RecyclerView rv, MotionEvent e) {

       }

       @Override
       public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {

       }
   });

也试过这个:

outerRecyclerView.setNestedScrollingEnabled(true);//Does not make any difference
innerRecyclerView.setNestedScrollingEnabled(true);//Recycler View start scrolling but very slowly and sometimes scrolls the outer one.

【问题讨论】:

  • 他们都需要垂直滚动?你期待什么样的行为?
  • 您可以尝试为外部回收器启用嵌套滚动并为内部禁用它吗?
  • 让两个嵌套视图在同一方向滚动是一个非常糟糕的主意。为什么需要这样做?
  • @DavidArgyleThacker 实际上,我在回收站视图中有展开/折叠类型的布局。当外部回收器视图的行展开时,它有另一个列表来显示属于该特定行的列表。这就是为什么,我有两个在同一方向滚动的回收站视图。如果您有更好的想法来完成此操作,请告诉我。
  • 如果您想要一个可扩展的回收站视图,那么您可以尝试:github.com/thoughtbot/expandable-recycler-view

标签: android android-recyclerview vertical-scrolling nestedrecyclerview


【解决方案1】:

将下面的 ontouch 监听器应用到可能位于父回收器适配器中的内部回收器。

RecyclerView.OnItemTouchListener mScrollTouchListener = new RecyclerView.OnItemTouchListener() {
@Override
public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
    int action = e.getAction();
    switch (action) {
        case MotionEvent.ACTION_MOVE:
            rv.getParent().requestDisallowInterceptTouchEvent(true);
            break;
    }
    return false;
}

@Override
public void onTouchEvent(RecyclerView rv, MotionEvent e) {

}

@Override
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {

}
}; 

innerrecyclerView.addOnItemTouchListener(mScrollTouchListener);

【讨论】:

  • 这适用于 RecyclerView 内可以向同一方向滚动的任何类型的视图
  • 这项工作与 RecyclerView 内部 RecyclerView 一起工作,谢谢
  • 但在这种情况下,我如何添加 onClick 侦听器,因为这种情况下,点击侦听器仅在 2 次点击时触发
  • 如果你想点击你设置触摸监听器的回收站,那么你可以通过这个link检测触摸监听器内部的点击。
【解决方案2】:

前段时间我在实现回收站视图时遇到了同样的问题。两个回收站视图都会开始滚动,对。尽管使用嵌套的回收器视图是一个坏主意,但如果您希望它正确滚动,则必须禁用内部的滚动。我不确定,但我认为是这样。让我知道它是否有效。如果没有,我会挖掘我的代码并尝试找到解决方案。

RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(parent.getContext()) {
            @Override
            public boolean canScrollVertically() {
                return false;
            }
        };

【讨论】:

  • 好的。我这样做的方法是使 inner 回收器视图不可滚动。所以在滚动时,只有外面的那个是活动的。这是一段代码。 ` RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(parent.getContext()) { @Override public boolean canScrollVertically() { return false; } }; innerRecyclerView.setLayoutManager(mLayoutManager);` 现在这段代码在第一个回收器视图适配器(外部回收器视图)的 onCreateViewHolder() 中。
  • @AndyRoid 我真的不记得我是怎么做到的了。您尝试进入 inner recyclerview 的 xml 布局并将布局高度作为包装内容并让我知道它是否有效(也禁用垂直滚动,就像我在之前的评论中提到的那样)。 android:layout_height="wrap_content"
【解决方案3】:

使用 android.support.v4.widget.NestedScrollView 而不是使用 ScrollView

这对我来说效果很好。

<android.support.v4.widget.NestedScrollView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    >
    <android.support.v7.widget.RecyclerView
            android:id="@+id/recyclerView"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:padding="4dp"
            />

</android.support.v4.widget.NestedScrollView>

【讨论】:

    【解决方案4】:

    你可以做的是,你可以添加一个滚动视图作为封装第二个回收器视图的视图持有者的根布局。

      <ScrollView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/subContainer"
        >
        <android.support.v7.widget.RecyclerView
            android:id="@+id/subList"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
             />
    </ScrollView>
    

    完成后,subList recycler view 可以充分利用 wrap_content 属性。现在,要使其正常工作,您需要禁用子列表回收器视图的垂直滚动。

    LinearLayoutManager layoutManager = new LinearLayoutManager(context) {
            @Override
            public boolean canScrollVertically() {
                return false;
            }
        }; 
    

    这样做,所有垂直滚动事件都将由父回收器视图处理。

    【讨论】:

    • 有没有办法让 innerRV 处理它自己的滚动事件?
    【解决方案5】:

    现在,要使其正常工作,您需要禁用子列表回收器视图的垂直滚动。

    LinearLayoutManager layoutManager = new LinearLayoutManager(context) {
                @Override
                public boolean canScrollVertically() {
                    return false;
                }
        }; 
    

    【讨论】:

      【解决方案6】:

      不要在回收站视图中保留回收站视图。相反,您应该夸大内部回收器视图。您可以在回收站视图的 onBindViewHolder 中拥有一个线性布局并膨胀该布局。通过这样做,您将永远不会遇到滚动问题。

      【讨论】:

        【解决方案7】:
        parentScroll.setOnTouchListener(new View.OnTouchListener() {
        
            public boolean onTouch(View v, MotionEvent event) {
        
                findViewById(R.id.childScroll).getParent()
                   .requestDisallowInterceptTouchEvent(false);
        
                return false;
             }
        });
        
        childScroll.setOnTouchListener(new View.OnTouchListener() {
        
              public boolean onTouch(View v, MotionEvent event) {  
        
                   v.getParent().requestDisallowInterceptTouchEvent(true);
                   return false;
              }
        });
        

        【讨论】:

        • 虽然此代码可能会解决问题,including an explanation 关于如何以及为什么解决问题将真正有助于提高您的帖子质量,并可能导致更多的赞成票。请记住,您正在为将来的读者回答问题,而不仅仅是现在提问的人。请edit您的回答添加解释并说明适用的限制和假设。
        【解决方案8】:

        为了 homever 可能有用,我做了一些我在一些帖子周围看到的东西。

        首先我做了一个自定义的 LinearLayoutManager 阻止垂直滚动。

            class CustomHorizontalLinearLayout(context: Context) :
        LinearLayoutManager(context, RecyclerView.HORIZONTAL, false) {
        
        override fun canScrollVertically(): Boolean {
            return false
        }
        

        并将其设置为子 RecyclerView(在本例中称为 RecommendationRV):

        itemView.recommendationRV?.apply {
                        adapter = recyclerViewAdapter
                        setRecycledViewPool(viewPool)
                        setLayoutManager(layoutManager)
                        setHasFixedSize(true)
                    }
        

        接下来我在子 RecyclerView ViewHolder XML 中添加了一个外部 NestedScrollView

        <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="220dp"
        android:orientation="vertical"
        android:background="@color/transparent"
        android:paddingVertical="10dp">
        
        <androidx.core.widget.NestedScrollView
            android:layout_width="match_parent"
            android:layout_height="match_parent">
            <androidx.recyclerview.widget.RecyclerView
                android:id="@+id/recommendationRV"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:background="@color/transparent"
                android:clickable="true"
                android:focusable="true"
                />
        </androidx.core.widget.NestedScrollView>
        

        这似乎奏效了。这可能不是最好的方法,但它对我来说就像一种魅力,所以我希望这可以帮助某人

        【讨论】:

          【解决方案9】:

          尝试使用此代码,它对我有用

          <androidx.core.widget.NestedScrollView
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:isScrollContainer="true">
          
              <androidx.recyclerview.widget.RecyclerView
                  android:id="@+id/recyclerView"
                  android:layout_width="match_parent"
                  android:layout_height="wrap_content"/>
          
           </androidx.core.widget.NestedScrollView>
          

          【讨论】:

            【解决方案10】:

            您不需要将 recyclerView 放在另一个 recyclerView 中。这根本不符合逻辑。如果你想在一个单一的布局 XML 中组合,只需按照以下步骤操作:

            • 将 NestedScrollView 设为父级
            • 在 NestedScrollView 中创建 LinerLayout
            • 将 RecyclerViews 放入 NestedScrollView

              <android.support.v4.widget.NestedScrollView
                      android:layout_width="match_parent"
                      android:layout_height="wrap_content">
              
                      <LinearLayout
                          android:orientation="vertical"
                          android:layout_width="match_parent"
                          android:layout_height="wrap_content">
              
                          <android.support.v7.widget.RecyclerView
                              android:id="@+id/firstRecycler"
                              android:layout_width="match_parent"
                              android:layout_height="wrap_content"/>
              
                          <android.support.v7.widget.RecyclerView
                              android:id="@+id/secondRecycler"
                              android:layout_width="match_parent"
                              android:layout_height="wrap_content"/>
              
                      </LinearLayout>
              </android.support.v4.widget.NestedScrollView>
              

            【讨论】: