Disposición de Android: Recyclerview horizontal dentro de una Recyclerview vertical dentro de un Viewpager con comportamientos de desplazamiento

Esta es la aplicación que estoy tratando de construir con todos los elementos trazados a continuación:

Aplicación Veggies

Todo funciona, sin embargo, quiero que el interior reciclerview horizontal no capturar ninguno de los rollos verticales. Todos los rollos verticales deben ir hacia la recuadra vertical externa, no horizontal, de modo que el desplazamiento vertical permita que la barra de herramientas salga fuera de la vista de acuerdo a su scrollFlag.

Cuando pongo mi dedo en la "planta de Strawberry" parte de la recyclerview y desplácese hacia arriba, desplácese hacia fuera la barra de herramientas:

Planta de fresa

Si coloco el dedo en la vista de desplazamiento horizontal y me desplazo hacia arriba, no se desplaza hacia fuera de la barra de herramientas en absoluto.

El siguiente es mi código de diseño xml hasta ahora.

El diseño de la actividad 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> 

El fragmento "Fruits" fragmento xml (que es el código para el fragmento – el fragmento está etiquetado en la imagen anterior):

 <?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> 

He utilizado una clase personalizada llamada VerticallyScrollRecyclerView que sigue el ejemplo de google de manejo de eventos táctiles en un grupo de vistas. Su objetivo es interceptar y consumir todos los eventos de desplazamiento vertical para que se desplace hacia adentro / hacia fuera de la barra de herramientas: http://developer.android.com/training/gestures/viewgroup.html

El código para VerticallyScrollRecyclerView está abajo:

 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; } } 

El diseño "Favorito" que es la vista de reciclaje dentro del reciclado vertical:

 <?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> 

Esto me ha estado molestando desde hace un tiempo y no he conseguido llegar a una solución. ¿Alguien sabe cómo solucionar este problema?

5 puntos a Griffindor para la respuesta correcta y, por supuesto, puntos de reputación en SO.

Solución probada:

Todo lo que necesitas es llamar a mInnerRecycler.setNestedScrollingEnabled(false); En su interior RecyclerView s

Explicación :

RecyclerView tiene soporte para desplazamiento anidado introducido en la API 21 mediante la implementación de la interfaz NestedScrollingChild . Esta es una característica valiosa cuando tiene una vista de desplazamiento dentro de otra que se desplaza en la misma dirección y desea desplazar la View interna sólo cuando se enfoca.

En cualquier caso, RecyclerView llama por defecto a RecyclerView.setNestedScrollingEnabled(true); En sí mismo al inicializar. Ahora, de vuelta al problema, ya que ambos de su RecyclerView s están dentro del mismo ViewPager que tiene el AppBarBehavior , el CoordinateLayout tiene que decidir qué desplazamiento responder cuando se desplaza de su interior RecyclerView ; Cuando el desplazamiento anidado de su RecyclerView interno está habilitado, obtiene el foco de desplazamiento y el CoordinateLayout escogerá responder a su desplazamiento sobre el desplazamiento externo de RecyclerView . La cosa es que, ya que su RecyclerView interna s no se desplaza verticalmente, no hay cambio de desplazamiento vertical (desde el punto de vista de CoordinateLayout ), y si no hay cambio, AppBarLayout tampoco cambia.

En su caso, debido a que su RecyclerView interna está desplazándose en una dirección diferente, puede desactivarla, haciendo que el CoordinateLayout haga caso omiso de su desplazamiento y responda al desplazamiento externo de RecyclerView .

Aviso :

El atributo xml android:nestedScrollingEnabled="boolean" no está destinado a ser usado con el RecyclerView , y un intento de usar android:nestedScrollingEnabled="false" resultará en una java.lang.NullPointerException así que, al menos por ahora, usted tendrá Para hacerlo en código.

Solución probada, utilice un NestedScrollView() personalizado NestedScrollView() .

Código:

 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); } } 

Estoy un poco tarde pero esto funcionará definitivamente para otros que enfrentan el mismo problema

  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; } 
  • Multiline EditText en los problemas de desplazamiento de RecyclerView
  • ¿Cómo utilizar ContentObserver con RecyclerView?
  • Android RecyclerView con GridLayoutManager hace que el artículo abarque varias filas
  • Recycler View Adapter con EditText
  • SwipeRefreshLayout sin animación en la creación de fragmentos
  • ¿Agregar un nuevo elemento a recyclerview de forma programática?
  • Android Recycler filtro adaptador de vista con animación
  • Facebook Anuncios nativos en RycyclerView android
  • Desplazamiento abrupto con NestedScrollView en ViewPager Fragmento dentro de un CoordinatorLayout Android
  • RecyclerView se desplaza hacia arriba en notifyDataSetChanged en la pantalla de chat
  • Cómo saltar la primera fila en RecyclerView elemento de decoración para GridLayout?
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.