android - example - ¿Cómo usar RecyclerView dentro de NestedScrollView?
scroll recyclerview (20)
¿Cómo usar
RecyclerView
dentro de
NestedScrollView
?
RecyclerView
contenido de
RecyclerView
no es visible después de configurar el adaptador.
ACTUALIZACIÓN del código de diseño actualizado.
<android.support.v4.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="@dimen/keyline_1">
</RelativeLayout>
<View
android:id="@+id/separator"
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#e5e5e5" />
<android.support.v7.widget.RecyclerView
android:id="@+id/conversation"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</android.support.v4.widget.NestedScrollView>
RecyclerView con NestedScrollView
<android.support.v7.widget.RecyclerView
android:id="@+id/rv"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
1) Debe usar la biblioteca de soporte 23.2.0 (o) anterior
2) y la altura de
RecyclerView
será
wrap_content
.
3)
recyclerView.setNestedScrollingEnabled(false)
Pero al hacer esto, el patrón de reciclador no funciona.
(es decir, todas las vistas se cargarán a la vez porque
wrap_content
necesita la altura de
RecyclerView
completa, por lo que dibujará todas las
View
secundarias a la vez. Ninguna vista se reciclará).
Intente no utilizar este patrón de utilidad a menos que sea realmente necesario.
Intente usar
viewType
y agregue todas las demás vistas que necesitan desplazarse a
RecyclerView
lugar de usar
RecyclerView
en
Scrollview
.
El impacto en el rendimiento será muy alto.
Para hacerlo simple, "simplemente actúa como
LinearLayout
con todas las vistas secundarias"
Aquí está el código que estoy usando para evitar problemas de desplazamiento:
mRecyclerView = (RecyclerView) view.findViewById(android.R.id.list);
mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
mRecyclerView.getLayoutManager().setAutoMeasureEnabled(true);
mRecyclerView.setNestedScrollingEnabled(false);
mRecyclerView.setHasFixedSize(false);
Hay muchas buenas respuestas.
La clave es que debe establecer
nestedScrollingEnabled
en
false
.
Como se mencionó anteriormente, puede hacerlo en código java:
mRecyclerView.setNestedScrollingEnabled(false);
Pero también tiene la oportunidad de establecer la misma propiedad en el código xml (
android:nestedScrollingEnabled="false"
):
<android.support.v7.widget.RecyclerView
android:id="@+id/recyclerview"
android:nestedScrollingEnabled="false"
android:layout_width="match_parent"
android:layout_height="match_parent" />
Hay un código simple y de prueba que puede verificar
<android.support.v4.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</android.support.v4.widget.NestedScrollView>
Intente utilizar esta biblioteca: https://github.com/serso/android-linear-layout-manager .
LayoutManager de la biblioteca hace que RecyclerView envuelva su contenido. En este caso, RecyclerView será "tan grande como las vistas internas", por lo que no tendrá barras de desplazamiento y el usuario utilizará las capacidades de desplazamiento de NestedScrollView. Por lo tanto, no será ambiguo como "desplazable dentro de desplazable".
No puede usar una vista de reciclador dentro de una vista de desplazamiento anidada. No está destinado a contener más vistas desplazables, pero es porque es un elemento secundario de un diseño de desplazamiento en sí mismo que necesita la vista de desplazamiento anidada. Tuve el mismo problema, pero al final moví mi vista de texto para que fuera una vista de encabezado dentro de la vista de reciclaje, hice que la vista de reciclaje fuera un elemento directo del diseño del coordinador y eliminé la vista de desplazamiento anidada. Entonces todos mis problemas se fueron.
Para
androidx
se llama
androidx.core.widget.NestedScrollView
, y también se desplaza por igual con las propiedades
isScrollContainer
y
measureAllChildren
habilitado:
<!-- Scrolling Content -->
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:isScrollContainer="true"
android:measureAllChildren="true"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fastScrollEnabled="true"
android:scrollbarStyle="insideInset"
android:scrollbars="vertical"
android:splitMotionEvents="false"
android:verticalScrollbarPosition="right"/>
</androidx.core.widget.NestedScrollView>
Puede usar
android:fillViewport="true"
para hacer que
NestedScrollView
mida el
RecyclerView
.
RecyclerView
llenará la altura restante.
así que si desea desplazarse por
NestScrollView
, puede configurar
NestScrollView
RecyclerView
.
Reemplace su recyclerView con,
<android.support.v7.widget.RecyclerView
android:id="@+id/conversation"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
aquí,
app:layout_behavior="@string/appbar_scrolling_view_behavior"
gestionará el resto de las cosas.
Una cosa más, no es necesario poner su reciclador Ver dentro de NestedScrollView
Si está utilizando
RecyclerView-23.2.1
o posterior.
La siguiente solución funcionará bien:
En su diseño, agregue RecyclerView así:
<android.support.v7.widget.RecyclerView
android:id="@+id/review_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scrollbars="vertical" />
Y en tu archivo java:
RecyclerView mRecyclerView = (RecyclerView) view.findViewById(R.id.recyclerView);
LinearLayoutManager layoutManager=new LinearLayoutManager(getContext());
layoutManager.setAutoMeasureEnabled(true);
mRecyclerView.setLayoutManager(layoutManager);
mRecyclerView.setHasFixedSize(true);
mRecyclerView.setAdapter(new YourListAdapter(getContext()));
Aquí
layoutManager.setAutoMeasureEnabled(true);
Hará el truco.
Consulte este tema y este blog de desarrolladores para obtener más información.
Si está utilizando RecyclerView ScrollListener dentro de NestedScrollView , addOnScrollListener oyente no funciona correctamente si se utilizan ambos.
Usa este código.
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
......
}
});
este código funciona bien RecyclerView ScrollListener dentro de NestedScrollView .
Gracias
Simplemente agregue
recyclerView.setNestedScrollingEnabled(false);
antes de que
setAdapter
funcionara para mí.
No
app:layout_behavior="@string/appbar_scrolling_view_behavior"
ninguna parte y no configuré ningún administrador de diseño personalizado
<android.support.v4.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="@color/white"
android:text="Some Text..."
android:padding="15dp" />
</LinearLayout>
<LinearLayout
android:orientation="vertical"
android:padding="15dp"
android:layout_marginTop="10dp"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Quick Links"
android:textColor="@color/black"
android:textStyle="bold"
android:textAllCaps="true"
android:paddingLeft="20dp"
android:drawableLeft="@drawable/ic_trending_up_black_24dp"
android:drawablePadding="10dp"
android:layout_marginBottom="10dp"
android:textSize="16sp"/>
<View
android:layout_width="fill_parent"
android:layout_height="1dp"
android:background="#efefef"/>
<android.support.v7.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/recyclerview"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
</LinearLayout>
</android.support.v4.widget.NestedScrollView>
Tengo Viewpager y RecyclerView dentro de NestedScrollView. Después de agregar las siguientes líneas
recyclerView.setNestedScrollingEnabled(false);
recyclerView.setHasFixedSize(false);
Resolví el problema de desplazamiento lento y retraso de desplazamiento.
Tuve que implementar CoordinatorLayout con el desplazamiento de la barra de herramientas y me llevó todo el día jugar con esto. Lo tengo funcionando eliminando NestedScrollView en absoluto. Así que solo estoy usando RelativeLayout en la raíz.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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.support.v7.widget.RecyclerView
android:id="@+id/rv_nearby"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
</RelativeLayout>
Una solución para mantener la función de reciclaje de la vista de reciclaje y evitar que la vista de reciclaje cargue todos sus datos es establecer una altura fija en la vista de reciclaje. Al hacer esto, la vista del reciclador se limita solo a cargar tanto como su altura pueda mostrar al usuario, reciclando así su elemento si alguna vez se desplaza hacia abajo / arriba.
no use recyclerView dentro de NestedScrollView. ¡Puede causar problemas en cascada! Sugiero usar ItemViewTypes en RecyclerView para manejar múltiples tipos de vistas. simplemente agregue un RecyclerView con match_parent ancho y alto. luego, en su recyclerViewAdapter, anule getItemViewType y use la posición para manejar qué diseño se inflará. después de eso, puede manejar su soporte de vista utilizando el método onBindViewHolder.
ACTUALIZACIÓN 1
Desde Android Support Library 23.2.0 se agregaron métodos
setAutoMeasureEnabled(true)
para LayoutManagers.
Hace que RecyclerView ajuste su contenido y funciona de maravilla.
http://android-developers.blogspot.ru/2016/02/android-support-library-232.html
Así que solo agrega algo como esto:
LayoutManager layoutManager = new LinearLayoutManager(this);
layoutManager.setAutoMeasureEnabled(true);
recyclerView.setLayoutManager(layoutManager);
recyclerView.setNestedScrollingEnabled(false);
ACTUALIZACIÓN 2
Dado que 27.1.0
setAutoMeasureEnabled
está en desuso, por lo que debe proporcionar una implementación personalizada de LayoutManager con el método anulado
isAutoMeasureEnabled()
Pero después de muchos casos de uso de RecyclerView, recomiendo no usarlo en modo envolvente , porque esto no es para lo que está destinado. Intente refactorizar todo su diseño utilizando RecyclerView normal con varios tipos de elementos. O utilice el enfoque con LinearLayout que describí a continuación como último recurso
Respuesta anterior (no recomendada)
Puede usar
RecyclerView
dentro de
NestedScrollView
.
En primer lugar, debe implementar su propio
LinearLayoutManager
personalizado, hace que su
RecyclerView
LinearLayoutManager
su contenido.
Por ejemplo:
public class WrappingLinearLayoutManager extends LinearLayoutManager
{
public WrappingLinearLayoutManager(Context context) {
super(context);
}
private int[] mMeasuredDimension = new int[2];
@Override
public boolean canScrollVertically() {
return false;
}
@Override
public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state,
int widthSpec, int heightSpec) {
final int widthMode = View.MeasureSpec.getMode(widthSpec);
final int heightMode = View.MeasureSpec.getMode(heightSpec);
final int widthSize = View.MeasureSpec.getSize(widthSpec);
final int heightSize = View.MeasureSpec.getSize(heightSpec);
int width = 0;
int height = 0;
for (int i = 0; i < getItemCount(); i++) {
if (getOrientation() == HORIZONTAL) {
measureScrapChild(recycler, i,
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
heightSpec,
mMeasuredDimension);
width = width + mMeasuredDimension[0];
if (i == 0) {
height = mMeasuredDimension[1];
}
} else {
measureScrapChild(recycler, i,
widthSpec,
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
mMeasuredDimension);
height = height + mMeasuredDimension[1];
if (i == 0) {
width = mMeasuredDimension[0];
}
}
}
switch (widthMode) {
case View.MeasureSpec.EXACTLY:
width = widthSize;
case View.MeasureSpec.AT_MOST:
case View.MeasureSpec.UNSPECIFIED:
}
switch (heightMode) {
case View.MeasureSpec.EXACTLY:
height = heightSize;
case View.MeasureSpec.AT_MOST:
case View.MeasureSpec.UNSPECIFIED:
}
setMeasuredDimension(width, height);
}
private void measureScrapChild(RecyclerView.Recycler recycler, int position, int widthSpec,
int heightSpec, int[] measuredDimension) {
View view = recycler.getViewForPosition(position);
if (view.getVisibility() == View.GONE) {
measuredDimension[0] = 0;
measuredDimension[1] = 0;
return;
}
// For adding Item Decor Insets to view
super.measureChildWithMargins(view, 0, 0);
RecyclerView.LayoutParams p = (RecyclerView.LayoutParams) view.getLayoutParams();
int childWidthSpec = ViewGroup.getChildMeasureSpec(
widthSpec,
getPaddingLeft() + getPaddingRight() + getDecoratedLeft(view) + getDecoratedRight(view),
p.width);
int childHeightSpec = ViewGroup.getChildMeasureSpec(
heightSpec,
getPaddingTop() + getPaddingBottom() + getDecoratedTop(view) + getDecoratedBottom(view),
p.height);
view.measure(childWidthSpec, childHeightSpec);
// Get decorated measurements
measuredDimension[0] = getDecoratedMeasuredWidth(view) + p.leftMargin + p.rightMargin;
measuredDimension[1] = getDecoratedMeasuredHeight(view) + p.bottomMargin + p.topMargin;
recycler.recycleView(view);
}
}
Después de eso, use este
LayoutManager
para su
RecyclerView
recyclerView.setLayoutManager(new WrappingLinearLayoutManager(getContext()));
Pero también debe llamar a esos dos métodos:
recyclerView.setNestedScrollingEnabled(false);
recyclerView.setHasFixedSize(false);
Aquí
setNestedScrollingEnabled(false)
deshabilita el desplazamiento para
RecyclerView
, por lo que no intercepta el evento de desplazamiento de
NestedScrollView
.
Y
setHasFixedSize(false)
determina que los cambios en el contenido del adaptador pueden cambiar el tamaño de
RecyclerView
Nota importante:
esta solución es poco defectuosa en algunos casos y tiene problemas con el rendimiento, por lo que si tiene muchos elementos en su
RecyclerView
, recomendaría usar una implementación de vista de lista basada en
LinearLayout
personalizada, crear un análogo del adaptador para ella y hacer que se comporte como
ListView
o
RecyclerView
Esto es lo que funciona para mi
<android.support.v4.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<android.support.v7.widget.RecyclerView
android:id="@+id/rv_recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_behavior="@string/appbar_scrolling_view_behavior"/>
</android.support.v4.widget.NestedScrollView>
Usé RecyclerView dentro de un NestedScrollView y funcionó para mí. El único problema que tuve que tener en cuenta fue que un NestedScrollView solo toma una vista secundaria. Entonces, en mi caso, utilicé el grupo de vista LienearLayout, que albergaba mi RecyclerView más otras vistas que necesitaba.
Experimento un problema al colocar mi RecyclerView dentro de NestedScrollView. Me di cuenta de que desplazar el contenido de mi RecyclerView se aflojó.
Más tarde me di cuenta de que mi RecyclerView estaba recibiendo el evento de desplazamiento y, por lo tanto, estaba en conflicto con el comportamiento de desplazamiento de NestedScrollView.
Entonces, para resolver ese problema, tuve que deshabilitar la funcionalidad de desplazamiento de mi RecyclerView con este método
movieListNewRecyclerView.setNestedScrollingEnabled(false);
Puedes ver mi Instagram para ver un video corto de lo que realmente hice. Este es mi identificador de instagram ofelix03