Ich erhalte ein seltsames Bildlaufverhalten, wenn ich eine RecyclerView in eine NestedScrollView einfüge.
Wenn die Bildlaufansicht mehr Zeilen enthält, als auf dem Bildschirm angezeigt werden können, beginnt die NestedScrollView nach dem Start der Aktivität mit einem Versatz von oben (Bild 1). Wenn die Bildlaufansicht nur wenige Elemente enthält, sodass alle gleichzeitig angezeigt werden können, geschieht dies nicht (Bild 2).
Ich verwende Version 23.2.0 der Support-Bibliothek.
Bild 1 : FALSCH - beginnt mit einem Versatz von oben
Bild 2 : RICHTIG - wenige Elemente in der Recycler-Ansicht
Ich füge unter meinem Layoutcode ein:
<?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>
Vermisse ich etwas Hat jemand eine Idee, wie man das behebt?
Update 1
Es funktioniert ordnungsgemäß, wenn ich beim Initialisieren meiner Aktivität den folgenden Code eingebe:
sv.post(new Runnable() {
@Override
public void run() {
sv.scrollTo(0,0);
}
});
Wobei sv ein Verweis auf NestedScrollView ist, sieht es jedoch nach einem ziemlichen Hack aus.
Update 2
Wie gewünscht, hier ist mein Adaptercode:
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());
}
}
Und hier ist mein 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);
}
}
Und hier ist das Layout jedes Elements in der RecyclerView (es ist nur android.R.layout.simple_spinner_item
- dieser Bildschirm dient nur zur Anzeige eines Beispiels für diesen Fehler):
<?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"
fürRecyclerView
? smth ist eindeutig "zwingen Sie Ihr Layout, nach unten zu gehen ... (wo es beginnt, wenn Sie 1295 Elemente haben? unten oder nur kleiner oberer Versatz wie der erste Bildschirm)LayoutManager
Antworten:
Ich habe dieses Problem gelöst, indem ich Folgendes eingestellt habe:
zu meiner Ansicht über RecyclerView (die nach unerwünschtem Scrollen ausgeblendet wurde). Versuchen Sie, diese Eigenschaft auf Ihr LinearLayout über RecyclerView oder auf LinearLayout festzulegen, das ein Container von RecyclerView ist (hat mir in einem anderen Fall geholfen).
Wie ich in der NestedScrollView-Quelle sehe, versucht es, das erste mögliche Kind in onRequestFocusInDescendants zu fokussieren, und wenn nur RecyclerView fokussierbar ist, gewinnt es.
Bearbeiten (danke an Waran): und für einen reibungslosen Bildlauf vergessen Sie nicht einzustellen
yourRecyclerView.setNestedScrollingEnabled(false);
quelle
android:focusableInTouchMode="false"
die recyclerView festlegen , damit Sie nicht für alle anderen Ansichten true festlegen müssen.Verwenden Sie es
LinearLayout
unmittelbar danach wie folgtNestedScrollView
android:descendantFocusability
BEARBEITEN
Da viele von ihnen diese Antwort nützlich finden, werden sie auch Erklärungen geben.
Die Verwendung von
descendantFocusability
wird hier angegeben . Und als derfocusableInTouchMode
über hier . Die Verwendung vonblocksDescendants
indescendantFocusability
ermöglicht es dem Kind also nicht, sich beim Berühren zu konzentrieren, und daher kann ungeplantes Verhalten gestoppt werden.Wie für
focusInTouchMode
beideAbsListView
undRecyclerView
ruft die MethodesetFocusableInTouchMode(true);
in ihrem Konstruktor standardmäßig so ist es nicht das Attribut in der XML - Layout zu verwenden , erforderlich.Und für
NestedScrollView
folgende Methode wird verwendet:Hier
setFocusable()
wird anstelle von Methode verwendetsetFocusableInTouchMode()
. Aber nach diesem Post ,focusableInTouchMode
sollte es sei denn , für bestimmte Bedingungen vermieden werden , da es die Übereinstimmung mit Android normales Verhalten bricht. Ein Spiel ist ein gutes Beispiel für eine Anwendung, die die im Touch-Modus fokussierbare Eigenschaft gut nutzen kann. Wenn MapView im Vollbildmodus wie in Google Maps verwendet wird, ist dies ein weiteres gutes Beispiel dafür, wo Sie im Touch-Modus fokussierbar verwenden können.quelle
blocksDescendants
, den Fokus aller Nachkommen zu blockieren. Ich bin nicht sicher, aber versuchen SiebeforeDescendants
recyclerView.setFocusable(false); nestedScrollView.requestFocus();
in LinearLayout Hat für mich funktioniert.
quelle
Ich hatte das gleiche Problem und habe NestedScrollView erweitert und fokussierende Kinder deaktiviert. Aus irgendeinem Grund hat RecyclerView immer um Fokus gebeten, auch wenn ich gerade die Schublade geöffnet und geschlossen habe.
quelle
RecyclerView
Haltern haben.In meinem Fall löst dieser Code mein Problem
Mein Layout enthält ein übergeordnetes Layout als NestedScrollView mit einem untergeordneten LinearLayout. Das LinearLayout hat die Ausrichtung "vertikal" und unterliegt RecyclerView und EditText. Referenz
quelle
Ich habe zwei Vermutungen.
Erstens: Versuchen Sie, diese Zeile in Ihre NestedScrollView einzufügen
Zweitens: Verwenden
als Ihre Elternansicht So
Meine letzte mögliche Lösung. Ich schwöre :)
quelle
Dieses Problem tritt aufgrund des Fokus der Recyclingansicht auf.
Automatisch wird der gesamte Fokus auf die Wiederverwendung der Ansicht verschoben, wenn die Größe des Bildschirms vergrößert wurde.
Hinzufügen
android:focusableInTouchMode="true"
zum ersten ChildView wieTextView
,Button
und so weiter (nicht aufViewGroup
wieLinear
,Relative
und so weiter) sinnvoll , das Problem aber API Stufe 25 und höher Lösung zu lösen funktioniert nicht.Fügen Sie einfach diese 2 Zeile in ChildView wie
TextView
,Button
und so weiter (nicht aufViewGroup
wieLinear
,Relative
und so weiter)Ich bin gerade auf API-Ebene 25 mit diesem Problem konfrontiert worden. Ich hoffe, andere Leute verschwenden keine Zeit damit.
Fügen Sie diese Zeile hinzu, um ein reibungsloses Scrollen in RecycleView zu ermöglichen
Das Hinzufügen dieser Attribute funktioniert jedoch nur mit API-Level 21 oder höher. Wenn Sie möchten, dass das Scrollen unter der API-Ebene 25 funktioniert, fügen Sie diese Zeile Ihrer Klasse hinzu
quelle
Fügen Sie im Java-Code nach dem Initialisieren von recyclerView und dem Festlegen des Adapters die folgende Zeile hinzu:
Sie können auch versuchen, das Layout mit einem relativen Layout zu umbrechen, damit die Ansichten an derselben Position bleiben, aber recyclerView (welcher Bildlauf) an erster Stelle in der XML-Hierarchie steht. Der letzte Vorschlag ein verzweifelter Versuch: p
quelle
Da ich zu spät antworte, kann ich aber jemand anderem helfen. Verwenden Sie einfach die unten stehende oder höhere Version in build.gradle auf App-Ebene, und das Problem wird behoben.
quelle
Um nach oben zu scrollen, rufen Sie einfach Folgendes auf
setcontentview
:quelle
android:descendantFocusability="blocksDescendants"
Fügen Sie einfach die ViewGroup in der NestedScrollView hinzu.quelle