La vue Recycler dans NestedScrollView fait démarrer scroll au milieu
j'obtiens un comportement de défilement bizarre quand j'ajoute un RecyclerView à l'intérieur D'un NestedScrollView.
ce qui se passe est que chaque fois que le scrollview a plus de lignes que ce qui peut être montré dans l'écran, dès que l'activité est lancée, le scrollview nested commence avec un décalage du 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 prise en charge.
Image 1 : FAUX - commence avec un décalage à partir du haut
Image 2 : CORRECT - quelques éléments dans le recycleur de vue
je collé 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 a une idée comment résoudre ce problème?
"1519130920 mise à jour" Update 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, cependant cela ressemble à un piratage.
Update 2
comme demandé, voici mon code 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 viseur:
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 le RecyclerView (c'est juste android.R.layout.simple_spinner_item
- cet écran est seulement pour montrer un exemple de ce bug):
<?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"/>
9 réponses
j'ai résolu une telle question en mettant:
<ImageView ...
android:focusableInTouchMode="true"/>
à mon point de vue au-dessus de RecyclerView (qui était caché après parchemin indésirable). Essayez de placer cette propriété à votre LinearLayout au-dessus de RecyclerView ou à LinearLayout qui est un conteneur de RecyclerView (m'a aidé dans un autre cas).
comme je le vois dans NestedScrollView source il essaie de concentrer le premier enfant possible dans onRequestFocusInDescendants et si seulement RecyclerView est focalisable il gagne.
Edit (merci à Waran): et pour lisse de défilement n'oubliez pas de mettre yourRecyclerView.setNestedScrollingEnabled(false);
dans votre LinearLayout
immédiatement après NestedScrollView
, utilisez android:descendantFocusability
de la manière suivante
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="10dp"
android:descendantFocusability="blocksDescendants">
MODIFIER
puisque beaucoup d'entre eux obtenir cette réponse utile, fournira également une explication.
l'utilisation de descendantFocusability
est donnée ici . Et à partir de focusableInTouchMode
sur ici .
Ainsi, l'utilisation de blocksDescendants
dans descendantFocusability
ne permet à son enfant de se concentrer tout en se touchant et donc un comportement non planifié peut être arrêté.
comme pour focusInTouchMode
, à la fois AbsListView
et RecyclerView
appelle la méthode setFocusableInTouchMode(true);
dans leur constructeur par défaut, il n'est donc pas nécessaire d'utiliser cet attribut dans vos layouts XML.
et pour NestedScrollView
la méthode suivante est utilisée:
private void initScrollView() {
mScroller = ScrollerCompat.create(getContext(), null);
setFocusable(true);
setDescendantFocusability(FOCUS_AFTER_DESCENDANTS);
setWillNotDraw(false);
final ViewConfiguration configuration = ViewConfiguration.get(getContext());
mTouchSlop = configuration.getScaledTouchSlop();
mMinimumVelocity = configuration.getScaledMinimumFlingVelocity();
mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();
}
ici, setFocusable()
méthode est utilisée au lieu de setFocusableInTouchMode()
. Mais selon ce post , focusableInTouchMode
doit être évitée à moins que pour certaines conditions car il brise la cohérence avec le comportement Androïde normal. Un jeu est un bon exemple d'application qui peut faire bon usage de la propriété focusable in touch mode. MapView, s'il est utilisé en plein écran comme dans Google Maps, est un autre bon exemple où vous pouvez utiliser le mode focalisable en mode touch correctement.
j'ai eu le même problème et sovled en étendant NestedScrollView et handicapant les enfants de mise au point. Pour une raison ou une autre, RecyclerView demandait toujours de se concentrer, même quand j'ouvrais et fermais le tiroir.
public class DummyNestedScrollView extends NestedScrollView {
public DummyNestedScrollView(Context context) {
super(context);
}
public DummyNestedScrollView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public DummyNestedScrollView(Context context, @Nullable AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
/**
* Fixind problem with recyclerView in nested scrollview requesting focus
* /q/recycler-view-inside-nestedscrollview-causes-scroll-to-start-in-the-middle-49273/"Request focus");
//super.requestChildFocus(child, focused);
}
/**
* /q/recycler-view-inside-nestedscrollview-causes-scroll-to-start-in-the-middle-49273/"Request focus descendants");
//return super.onRequestFocusInDescendants(direction, previouslyFocusedRect);
return false;
}
}
android:descendantFocusability="blocksDescendants"
dans LinearLayout a fonctionné pour moi .
Dans mon cas, ce code résout mine problème
RecyclerView recyclerView = findViewById(R.id.recyclerView);
NestedScrollView nestedScrollView= findViewById(R.id.nestedScrollView);
recyclerView.setFocusable(false);
nestedScrollView.requestFocus();
//populate recyclerview here
ma mise en page contient une mise en page parent comme NestedScrollView qui a une sortie de ligne enfant. L'affichage en ligne a une orientation "verticale" et childs RecyclerView et EditText. référence
j'ai deux hypothèses.
D'abord: essayez de mettre cette ligne sur votre NestedScrollView
app:layout_behavior="@string/appbar_scrolling_view_behavior"
Second: Use
<android.support.design.widget.CoordinatorLayout
comme point de vue de vos parents Comme ceci
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v4.widget.NestedScrollView
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:orientation="vertical"
android:padding="16dp">
<TextView
style="@style/TextAppearance.AppCompat.Caption"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Title:"/>
<TextView
style="@style/TextAppearance.AppCompat.Body1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="@dimen/bodyPadding"
android:text="Neque porro quisquam est qui dolorem ipsum"/>
<TextView
style="@style/TextAppearance.AppCompat.Caption"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Subtitle:"/>
<TextView
style="@style/TextAppearance.AppCompat.Body1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
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:layout_width="match_parent"
android:layout_height="wrap_content"
android:focusable="false"/>
</LinearLayout>
</android.support.v4.widget.NestedScrollView>
ma dernière solution. Je vous jure :)
en code Java, après initialisation de votre recyclerView et paramétrage de l'adaptateur, ajouter cette ligne:
recyclerView.setNestedScrollingEnabled(false)
vous pouvez également essayer d'envelopper la mise en page avec un affichage relatif de sorte que les vues restent à la même position mais recyclerView (qui fait défiler) est le premier dans la hiérarchie xml. La dernière suggestion une tentative désespérée: p
comme je suis en retard dans la réponse, mais peut aider quelqu'un d'autre. Il suffit d'utiliser la version ci-dessous ou supérieure dans votre construction au niveau de l'application.Grad et le problème est supprimé.
compile com.android.support:recyclerview-v7:23.2.1
pour faire défiler vers le haut, il suffit de l'appeler setcontentview
:
scrollView.SmoothScrollTo(0, 0);