Android布局:使用滚动行为的Viewpager中的垂直RecyclerView内的水平RecyclerView

这是我试图build立与所有元素映射下面的应用程序:

蔬菜应用程序

一切正常,但是,我想内部水平recyclerview不捕捉任何垂直滚动。 所有的垂直卷轴都必须朝向外部垂直recyclerview,而不是水平卷轴,因此垂直卷轴将允许工具栏根据其scrollFlag退出视图。

当我将手指放在recyclerview的“StrawBerry Plant”部分并向上滚动时,它将滚动出工具栏:

草莓植物

如果我将手指放在水平滚动视图上并向上滚动,则根本不会滚出工具栏。

以下是我到目前为止的xml布局代码。

活动 xml布局:

<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/fragment_container" android:clipChildren="false"> <android.support.design.widget.CoordinatorLayout android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/container" > <android.support.design.widget.AppBarLayout android:id="@+id/appBarLayout" android:layout_width="match_parent" android:layout_height="wrap_content"> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:minHeight="?attr/actionBarSize" android:background="?attr/colorPrimary" android:layout_width="match_parent" android:layout_height="wrap_content" app:layout_scrollFlags="scroll|enterAlways"> </android.support.v7.widget.Toolbar> <android.support.design.widget.TabLayout android:id="@+id/sliding_tabs" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="?attr/colorPrimary" style="@style/CustomTabLayout" /> </android.support.design.widget.AppBarLayout> <android.support.v4.view.ViewPager android:id="@+id/viewPager" android:layout_width="match_parent" android:layout_height="match_parent" app:layout_behavior="@string/appbar_scrolling_view_behavior" /> </android.support.design.widget.CoordinatorLayout> </FrameLayout> 

“水果”片段的 XML布局(这是片段的代码 – 该片段在上图中标记):

 <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <ProgressBar android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/progressBar" android:visibility="gone" android:layout_centerInParent="true" android:indeterminate="true"/> <!-- <android.support.v7.widget.RecyclerView--> <com.example.simon.customshapes.VerticallyScrollRecyclerView android:id="@+id/main_recyclerview" android:layout_width="match_parent" android:layout_height="match_parent" /> </RelativeLayout> 

我使用了一个名为VerticallyScrollRecyclerView的自定义类,它遵循处理视图组中的触摸事件的谷歌示例。 它的目的是拦截和消耗所有的垂直滚动事件,以便它将滚动/滑出工具栏: http : //developer.android.com/training/gestures/viewgroup.html

VerticallyScrollRecyclerView的代码如下:

 public class VerticallyScrollRecyclerView extends RecyclerView { public VerticallyScrollRecyclerView(Context context) { super(context); } public VerticallyScrollRecyclerView(Context context, AttributeSet attrs) { super(context, attrs); } public VerticallyScrollRecyclerView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } ViewConfiguration vc = ViewConfiguration.get(this.getContext()); private int mTouchSlop = vc.getScaledTouchSlop(); private boolean mIsScrolling; private float startY; @Override public boolean onInterceptTouchEvent(MotionEvent ev) { final int action = MotionEventCompat.getActionMasked(ev); // Always handle the case of the touch gesture being complete. if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) { // Release the scroll. mIsScrolling = false; startY = ev.getY(); return super.onInterceptTouchEvent(ev); // Do not intercept touch event, let the child handle it } switch (action) { case MotionEvent.ACTION_MOVE: { Log.e("VRecView", "its moving"); if (mIsScrolling) { // We're currently scrolling, so yes, intercept the // touch event! return true; } // If the user has dragged her finger horizontally more than // the touch slop, start the scroll // left as an exercise for the reader final float yDiff = calculateDistanceY(ev.getY()); Log.e("yDiff ", ""+yDiff); // Touch slop should be calculated using ViewConfiguration // constants. if (Math.abs(yDiff) > 5) { // Start scrolling! Log.e("Scroll", "we are scrolling vertically"); mIsScrolling = true; return true; } break; } } return super.onInterceptTouchEvent(ev); } private float calculateDistanceY(float endY) { return startY - endY; } } 

垂直回收视图内回收视图的“collections”布局

 <?xml version="1.0" encoding="utf-8"?> <RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent" xmlns:android="http://schemas.android.com/apk/res/android" android:background="@color/white" xmlns:app="http://schemas.android.com/apk/res-auto"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Favourite" android:layout_marginTop="8dp" android:layout_marginBottom="8dp" android:layout_marginLeft="16dp" android:id="@+id/header_fav"/> <android.support.v7.widget.RecyclerView android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:layout_below="@+id/header_fav" android:id="@+id/recyclerview_fav"> </android.support.v7.widget.RecyclerView> </RelativeLayout> 

这一直困扰着我一段时间,我还没有设法提出一个解决scheme。 有谁知道如何解决这个问题?

5点Griffindor正确的答案,当然,SO的声望点。

Solutions Collecting From Web of "Android布局:使用滚动行为的Viewpager中的垂直RecyclerView内的水平RecyclerView"

testing的解决scheme:

所有你需要的是调用mInnerRecycler.setNestedScrollingEnabled(false); 在你的内在RecyclerView

说明

RecyclerView支持通过实现NestedScrollingChild接口在API 21引入的嵌套滚动。 这是一个很有价值的function,当你在另一个滚动视图的同一个方向滚动的时候,你只想在聚焦的时候滚动内部View

无论如何, RecyclerView默认调用RecyclerView.setNestedScrollingEnabled(true); 在初始化时。 现在,回到问题中,由于您的RecyclerView都在具有AppBarBehavior的相同ViewPager中, CoordinateLayout必须决定从内部RecyclerView滚动时要响应哪个滚动; 当启用内部RecyclerView的嵌套滚动时,它将获得滚动焦点, CoordinateLayout将select响应滚动外部RecyclerView的滚动。 问题是,由于你的内部RecyclerView不垂直滚动,没有垂直滚动的变化(从CoordinateLayout的angular度来看),如果没有改变, AppBarLayout也不会改变。

在你的情况下,因为你的内部RecyclerView在不同的方向上滚动,所以你可以禁用它,从而导致CoordinateLayout忽略它的滚动并响应外部的RecyclerView的滚动。

注意

xml属性android:nestedScrollingEnabled="boolean"不能与RecyclerView一起使用,而使用android:nestedScrollingEnabled="false"的尝试将导致java.lang.NullPointerExceptionexception,因此至less现在您将拥有在代码中完成。

经testing的解决scheme,使用自定义的NestedScrollView()

码:

 public class CustomNestedScrollView extends NestedScrollView { public CustomNestedScrollView(Context context, AttributeSet attrs) { super(context, attrs); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { if (ev.getAction() == MotionEvent.ACTION_DOWN) { // Explicitly call computeScroll() to make the Scroller compute itself computeScroll(); } return super.onInterceptTouchEvent(ev); } } 

我有点晚了,但是这样做肯定会为面临同样问题的其他人工作

  mRecyclerView.addOnItemTouchListener(new RecyclerView.OnItemTouchListener() { @Override public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) { int action = e.getAction(); // Toast.makeText(getActivity(),"HERE",Toast.LENGTH_SHORT).show(); switch (action) { case MotionEvent.ACTION_POINTER_UP: rv.getParent().requestDisallowInterceptTouchEvent(true); break; } return false; }