J'obtiens un comportement de défilement étrange lorsque j'ajoute un RecyclerView dans un NestedScrollView.
Ce qui se passe, c'est que chaque fois que la vue de défilement a plus de lignes que ce qui peut être affiché à l'écran, dès que l'activité est lancée, NestedScrollView commence par un décalage par rapport au haut (image 1). S'il y a peu d'éléments dans la vue de défilement pour qu'ils puissent tous être affichés en même temps, cela ne se produit pas (image 2).
J'utilise la version 23.2.0 de la bibliothèque de support.
Image 1 : MAUVAIS - commence par un décalage à partir du haut
Image 2 : CORRECT - quelques articles dans la vue du recycleur
Je colle sous mon code de mise en page:
<?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>
Est-ce que je manque quelque chose? Quelqu'un at-il une idée de la façon de résoudre ce problème?
Mise à jour 1
Cela fonctionne correctement si je place le code suivant lors de l'initialisation de mon activité:
sv.post(new Runnable() {
@Override
public void run() {
sv.scrollTo(0,0);
}
});
Où sv est une référence à NestedScrollView, mais cela ressemble à un hack.
Mise à jour 2
Comme demandé, voici mon code d'adaptateur:
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());
}
}
Et voici mon 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);
}
}
Et voici la disposition de chaque élément dans RecyclerView (c'est juste android.R.layout.simple_spinner_item
- cet écran est uniquement pour montrer un exemple de ce bogue):
<?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"/>
la source
android:focusableInTouchMode="false"
pourRecyclerView
? smth "oblige clairement votre mise en page à aller en bas ... (où elle commence lorsque vous avez 1295 éléments? bas ou juste un petit décalage supérieur comme le premier écran)LayoutManager
Réponses:
J'ai résolu ce problème en définissant:
à mon avis au-dessus de RecyclerView (qui était caché après un défilement indésirable). Essayez de définir cette propriété sur votre LinearLayout au-dessus de RecyclerView ou sur LinearLayout qui est le conteneur de RecyclerView (m'a aidé dans un autre cas).
Comme je le vois dans la source NestedScrollView, il essaie de concentrer le premier enfant possible dans onRequestFocusInDescendants et si seul RecyclerView est focalisable, il gagne.
Modifier (grâce à Waran): et pour un défilement fluide, n'oubliez pas de définir
yourRecyclerView.setNestedScrollingEnabled(false);
la source
android:focusableInTouchMode="false"
sur recyclerView afin que vous n'ayez pas besoin de définir true pour toutes les autres vues.Dans votre
LinearLayout
immédiatement aprèsNestedScrollView
, utilisezandroid:descendantFocusability
de la manière suivanteÉDITER
Étant donné que beaucoup d'entre eux obtiennent cette réponse utile, fournira également des explications.
L'utilisation de
descendantFocusability
est donnée ici . Et comme defocusableInTouchMode
plus ici . Donc, utiliserblocksDescendants
dansdescendantFocusability
ne permet pas à son enfant de se concentrer tout en touchant et donc un comportement imprévu peut être arrêté.Quant à
focusInTouchMode
, les deuxAbsListView
etRecyclerView
appelle la méthodesetFocusableInTouchMode(true);
dans leur constructeur par défaut, il n'est donc pas nécessaire d'utiliser cet attribut dans vos mises en page XML.Et pour la
NestedScrollView
méthode suivante est utilisée:Ici, la
setFocusable()
méthode est utilisée à la place desetFocusableInTouchMode()
. Mais selon ce post ,focusableInTouchMode
devrait être évité sauf dans certaines conditions, car cela rompt la cohérence avec le comportement normal d'Android. Un jeu est un bon exemple d'application qui peut faire bon usage de la propriété focusable en mode tactile. MapView, s'il est utilisé en plein écran comme dans Google Maps, est un autre bon exemple où vous pouvez utiliser correctement la mise au point en mode tactile.la source
blocksDescendants
bloquer le focus de tous les descendants. Je ne suis pas sûr, mais essayezbeforeDescendants
recyclerView.setFocusable(false); nestedScrollView.requestFocus();
à l'intérieur de LinearLayout a fonctionné pour moi.
la source
J'ai eu le même problème et j'ai résolu en étendant NestedScrollView et en désactivant la focalisation des enfants. Pour une raison quelconque, RecyclerView a toujours demandé la mise au point même lorsque je viens d'ouvrir et de fermer le tiroir.
la source
RecyclerView
.Dans mon cas, ce code résout le problème du mien
Ma mise en page contient une mise en page parent en tant que NestedScrollView qui a un enfant LinearLayout. Le LinearLayout a une orientation "verticale" et les fils RecyclerView et EditText. Référence
la source
J'ai deux suppositions.
Premièrement: essayez de mettre cette ligne sur votre NestedScrollView
Deuxièmement: utiliser
comme votre parent le voit comme ça
Ma dernière solution possible. Je le jure :)
la source
Ce problème survient en raison de la vue de recyclage Focus.
Automatiquement, tout le focus est passé à la vue de recyclage si sa taille étendait la taille de l'écran.
l'ajout
android:focusableInTouchMode="true"
au premier ChildView commeTextView
,Button
et ainsi de suite (pasViewGroup
commeLinear
,Relative
et ainsi de suite) a du sens pour résoudre le problème, mais la solution de niveau d'API 25 et plus ne fonctionne pas.Ajoutez simplement ces 2 lignes dans votre ChildView comme
TextView
,Button
et ainsi de suite (pas surViewGroup
commeLinear
,Relative
et ainsi de suite)Je viens de faire face à ce problème au niveau de l'API 25. J'espère que d'autres personnes ne perdront pas de temps là-dedans.
Pour un défilement fluide sur RecycleView, ajoutez cette ligne
mais l'ajout de ces attiributes ne fonctionne qu'avec le niveau d'API 21 ou supérieur. Si vous voulez que le défilement de lissage fonctionne au-dessous du niveau d'API 25, ajoutez cette ligne dans votre classe
la source
Dans le code Java, après avoir initialisé votre recyclerView et défini l'adaptateur, ajoutez cette ligne:
Vous pouvez également essayer d'encapsuler la mise en page avec un relativeLayout afin que les vues restent à la même position, mais recyclerView (qui défile) est le premier dans la hiérarchie XML. La dernière suggestion une tentative désespérée: p
la source
Comme je suis en retard pour répondre, mais peut aider quelqu'un d'autre. Utilisez simplement la version ci-dessous ou supérieure dans votre build.gradle au niveau de l'application et le problème est supprimé.
la source
pour faire défiler vers le haut, il suffit d'appeler ceci
setcontentview
:la source
Ajoutez simplement
android:descendantFocusability="blocksDescendants"
le ViewGroup à l'intérieur du NestedScrollView.la source