Estoy obteniendo un comportamiento de desplazamiento extraño cuando agrego un RecyclerView dentro de un NestedScrollView.
Lo que sucede es que cada vez que la vista de desplazamiento tiene más filas de las que se pueden mostrar en la pantalla, tan pronto como se inicia la actividad, NestedScrollView comienza con un desplazamiento desde la parte superior (imagen 1). Si hay pocos elementos en la vista de desplazamiento para que se puedan mostrar todos a la vez, esto no sucede (imagen 2).
Estoy usando la versión 23.2.0 de la biblioteca de soporte.
Imagen 1 : INCORRECTO: comienza con desplazamiento desde la parte superior
Imagen 2 : CORRECTO: pocos elementos en la vista de reciclador
Estoy pegando debajo de mi código de diseño:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="fill_vertical"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="10dp">
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="16dp"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Title:"
style="@style/TextAppearance.AppCompat.Caption"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="@dimen/bodyPadding"
style="@style/TextAppearance.AppCompat.Body1"
android:text="Neque porro quisquam est qui dolorem ipsum"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Subtitle:"
style="@style/TextAppearance.AppCompat.Caption"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@style/TextAppearance.AppCompat.Body1"
android:padding="@dimen/bodyPadding"
android:text="Neque porro quisquam est qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit..."/>
</LinearLayout>
<android.support.v7.widget.RecyclerView
android:id="@+id/rv"
android:focusable="false"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</android.support.v4.widget.NestedScrollView>
¿Me estoy perdiendo de algo? ¿Alguien tiene alguna idea de cómo solucionar este problema?
Actualización 1
Funciona correctamente si coloco el siguiente código al inicializar mi Actividad:
sv.post(new Runnable() {
@Override
public void run() {
sv.scrollTo(0,0);
}
});
Donde sv es una referencia a NestedScrollView, sin embargo, parece un gran truco.
Actualización 2
Según lo solicitado, aquí está mi código de adaptador:
public abstract class ArrayAdapter<T, VH extends RecyclerView.ViewHolder>
extends RecyclerView.Adapter<VH> {
private List<T> mObjects;
public ArrayAdapter(final List<T> objects) {
mObjects = objects;
}
/**
* Adds the specified object at the end of the array.
*
* @param object The object to add at the end of the array.
*/
public void add(final T object) {
mObjects.add(object);
notifyItemInserted(getItemCount() - 1);
}
/**
* Remove all elements from the list.
*/
public void clear() {
final int size = getItemCount();
mObjects.clear();
notifyItemRangeRemoved(0, size);
}
@Override
public int getItemCount() {
return mObjects.size();
}
public T getItem(final int position) {
return mObjects.get(position);
}
public long getItemId(final int position) {
return position;
}
/**
* Returns the position of the specified item in the array.
*
* @param item The item to retrieve the position of.
* @return The position of the specified item.
*/
public int getPosition(final T item) {
return mObjects.indexOf(item);
}
/**
* Inserts the specified object at the specified index in the array.
*
* @param object The object to insert into the array.
* @param index The index at which the object must be inserted.
*/
public void insert(final T object, int index) {
mObjects.add(index, object);
notifyItemInserted(index);
}
/**
* Removes the specified object from the array.
*
* @param object The object to remove.
*/
public void remove(T object) {
final int position = getPosition(object);
mObjects.remove(object);
notifyItemRemoved(position);
}
/**
* Sorts the content of this adapter using the specified comparator.
*
* @param comparator The comparator used to sort the objects contained in this adapter.
*/
public void sort(Comparator<? super T> comparator) {
Collections.sort(mObjects, comparator);
notifyItemRangeChanged(0, getItemCount());
}
}
Y aquí está mi ViewHolder:
public class ViewHolder extends RecyclerView.ViewHolder {
private TextView txt;
public ViewHolder(View itemView) {
super(itemView);
txt = (TextView) itemView;
}
public void render(String text) {
txt.setText(text);
}
}
Y aquí está el diseño de cada elemento en RecyclerView (es solo que android.R.layout.simple_spinner_item
esta pantalla es solo para mostrar un ejemplo de este error):
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/text1"
style="?android:attr/spinnerItemStyle"
android:singleLine="true"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="marquee"
android:textAlignment="inherit"/>
android:focusableInTouchMode="false"
paraRecyclerView
? smth claramente está "obligando a su diseño a ir a la parte inferior ... (¿dónde comienza cuando tiene 1295 elementos? inferior o simplemente un pequeño desplazamiento superior como la primera pantalla)LayoutManager
Respuestas:
Resolví tal problema estableciendo:
a mi vista sobre RecyclerView (que estaba oculto después de un desplazamiento no deseado). Intente establecer esta propiedad en su LinearLayout sobre RecyclerView o en LinearLayout, que es el contenedor de RecyclerView (me ayudó en otro caso).
Como veo en la fuente NestedScrollView, trata de enfocar al primer hijo posible en onRequestFocusInDescendants y si solo RecyclerView es enfocable, gana.
Editar (gracias a Waran): y para un desplazamiento suave, no olvide configurar
yourRecyclerView.setNestedScrollingEnabled(false);
fuente
android:focusableInTouchMode="false"
a recyclerView para que no necesite establecer true para todas las demás vistas.En su
LinearLayout
después inmediataNestedScrollView
, el usoandroid:descendantFocusability
de la siguiente maneraEDITAR
Dado que muchos de ellos obtienen esta respuesta útil, también proporcionarán una explicación.
El uso de
descendantFocusability
se da aquí . Y a partir defocusableInTouchMode
más de aquí . Por lo tanto, usarblocksDescendants
indescendantFocusability
no permite que su hijo se enfoque mientras toca y, por lo tanto, se puede detener el comportamiento no planificado.En cuanto a
focusInTouchMode
, ambosAbsListView
yRecyclerView
llama al métodosetFocusableInTouchMode(true);
en su constructor de forma predeterminada, por lo que no es necesario usar ese atributo en sus diseños XML.Y para el
NestedScrollView
siguiente método se utiliza:Aquí,
setFocusable()
se usa el método en lugar desetFocusableInTouchMode()
. Pero de acuerdo con esta publicación ,focusableInTouchMode
debe evitarse a menos que se den ciertas condiciones, ya que rompe la coherencia con el comportamiento normal de Android. Un juego es un buen ejemplo de una aplicación que puede hacer un buen uso de la propiedad enfocable en modo táctil. MapView, si se usa en pantalla completa como en Google Maps, es otro buen ejemplo de dónde puede usar correctamente el enfoque en modo táctil.fuente
blocksDescendants
bloquear el enfoque de todos los descendientes. No estoy seguro, pero pruebabeforeDescendants
recyclerView.setFocusable(false); nestedScrollView.requestFocus();
inside LinearLayout funcionó para mí.
fuente
Tuve el mismo problema y me molesté al extender NestedScrollView y deshabilitar enfocar a los niños. Por alguna razón, RecyclerView siempre solicitó enfoque incluso cuando abrí y cerré el cajón.
fuente
RecyclerView
titulares.En mi caso, este código resuelve el problema mío
Mi diseño contiene un diseño primario como NestedScrollView que tiene un LinearLayout secundario. LinearLayout tiene orientación "vertical" y ChildRecyclerView y EditText. Referencia
fuente
Tengo dos conjeturas.
Primero: intente poner esta línea en su NestedScrollView
Segundo: uso
como la vista de tus padres Me gusta esto
Mi última solución posible. Lo juro :)
fuente
Este problema llega debido a la vista de reciclaje Focus.
Automáticamente, todo el foco se ha ido a la vista de reciclaje si su tamaño amplía el tamaño de la pantalla.
añadiendo
android:focusableInTouchMode="true"
al primer ChildView comoTextView
,Button
y así sucesivamente (no enViewGroup
comoLinear
,Relative
y así sucesivamente) tiene sentido para resolver el problema, pero la API de nivel 25 y por encima de solución no funciona.Simplemente agregue estas 2 líneas en su ChildView como
TextView
,Button
y así sucesivamente (NoViewGroup
comoLinear
,Relative
y así sucesivamente )Acabo de enfrentar este problema en el nivel 25 de API. Espero que otras personas no pierdan el tiempo en esto.
Para un desplazamiento suave en RecycleView, agregue esta línea
pero agregar estos atributos solo funciona con el nivel de API 21 o superior. Si desea que el desplazamiento de suavizado funcione por debajo del nivel 25 de API, agregue esta línea en su clase
fuente
En el código Java, después de inicializar su recyclerView y configurar el adaptador, agregue esta línea:
También puede intentar ajustar el diseño con un diseño relativo para que las vistas permanezcan en la misma posición pero recyclerView (que se desplaza) es el primero en la jerarquía xml. La última sugerencia es un intento desesperado: p
fuente
Como llego tarde en responder, pero puede ayudar a alguien más. Simplemente use la versión siguiente o superior en el nivel de aplicación build.gradle y el problema se eliminará.
fuente
para desplazarse a la parte superior, solo llame a esto en
setcontentview
:fuente
Simplemente agregue
android:descendantFocusability="blocksDescendants"
el ViewGroup dentro de NestedScrollView.fuente