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:
- ¿Por qué ListView y RecyclerView son focusableInTouchMode?
- Cómo implementar filtrado en RealmRecyclerViewAdapter
- El trabajo de CollapsingTolbar con fagment contiene SwipeRefreshLayout y RecycleView
- Recuperando onBindViewHolder al desplazarse por la vista Recycler
- RecyclerView con CollapsingToolbarLayout se desplaza mal cuando se lanza
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:
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.
- Android: Recyclerview horizontal dentro de una Recyclerview vertical
- RecyclerView está cortando el último elemento
- Problemas de procesamiento: java.lang.NullPointerException en android.support.v7.widget.RecyclerView en Android Studio 1.1.0
- Animar las adiciones de RecyclerView desde abajo
- RecyclerView onItemClick Listener
- Problemas para conseguir que el video se reproduzca en Recyclerview
- ¿Cuál es la mejora de RecyclerView sobre ListView?
- Diseño como la aplicación HotStar
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; }