Ich benutze die neue RecyclerView-Layout in einem SwipeRefreshLayout und erlebte ein seltsames Verhalten. Beim Zurückscrollen der Liste nach oben wird manchmal die Ansicht oben abgeschnitten.
Wenn ich jetzt versuche, nach oben zu scrollen, wird der Pull-To-Refresh ausgelöst.
Wenn ich versuche das Swipe-Refresh-Layout um die Recycler-Ansicht herum zu entfernen, ist das Problem weg. Und es ist auf jedem Telefon reproduzierbar (nicht nur auf L-Preview-Geräten).
Und der Code der Fragment enthält die Recycler und die SwipeRefreshLayout.
Hat jemand anderes dieses Verhalten erlebt und gelöst oder zumindest den Grund dafür gefunden?
Ich hatte genau das gleiche Problem. Außerdem ist mir aufgefallen, dass RecyclerView von getScrollY() immer 0 zurückgibt. Vielleicht ist dies logisch, da verschiedene LayoutManager ausgetauscht werden können, nicht unbedingt scrollende. Ich bin mir nicht sicher, weil ich nicht weiter recherchiert habe. Ich freue mich, eine Lösung zu finden, werde die Antwort aber positiv bewerten, wenn ich sie nach meinem Urlaub in zwei Wochen testen kann.
– Cybergen
14. August 2014 um 18:10 Uhr
Lukas Olsen, dass “texturiert” unglaublich aussieht.
– Jared Burrows
29. Oktober 2014 um 3:06 Uhr
Krunal Patel
schreiben Sie den folgenden Code hinein addOnScrollListener des RecyclerView
So was:
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener(){
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
int topRowVerticalPosition =
(recyclerView == null || recyclerView.getChildCount() == 0) ? 0 : recyclerView.getChildAt(0).getTop();
swipeRefreshLayout.setEnabled(topRowVerticalPosition >= 0);
}
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
}
});
Ich verwende Recyclerview – nicht Listview
– Lukas Olsen
8. August 2014 um 10:58 Uhr
Nur um die Antwort ein wenig zu erweitern: Falls Sie die Polsterung für Ihre Elemente mithilfe von festlegen addItemDecoration und haben auch eine obere Polsterung auf der ReyclerView selbst würden Sie Ihre umschalten SwipeRefreshLayout wie folgt: boolean canEnableSwipeRefresh = mLayoutManager.findFirstVisibleItemPosition() == 0 && recyclerView.getChildAt(0).getTop() - (offset + mRecView.getPaddingTop()) == 0; wo offset wenn die obere Polsterung Ihrer Artikel
– Droidenmann
10. Dezember 2014 um 11:53 Uhr
@krunalpatel Ihre Parameter für onScrollStateChanged sind falsch. Sie sollten sein: onScrollStateChanged(RecyclerView recyclerView, int scrollState)
– IgorGanapolsky
7. Januar 2015 um 20:43 Uhr
recyclerView.setOnScrollListener ist veraltet, verwenden Sie stattdessen addOnScrollListener
– jiawen
11. November 2015 um 5:31 Uhr
tom91136
Bevor Sie diese Lösung verwenden: RecyclerView ist noch nicht vollständig. VERSUCHEN SIE, ES NICHT IN DER PRODUKTION ZU VERWENDEN, ES SEI DENN, SIE SIND WIE ICH!
Wie für November 2014 gibt es immer noch Fehler in RecyclerView, die dazu führen würden canScrollVertically falsch vorzeitig zurückzugeben. Diese Lösung löst alle Probleme beim Scrollen.
Die Drop-in-Lösung:
public class FixedRecyclerView extends RecyclerView {
public FixedRecyclerView(Context context) {
super(context);
}
public FixedRecyclerView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public FixedRecyclerView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
public boolean canScrollVertically(int direction) {
// check if scrolling up
if (direction < 1) {
boolean original = super.canScrollVertically(direction);
return !original && getChildAt(0) != null && getChildAt(0).getTop() < 0 || original;
}
return super.canScrollVertically(direction);
}
}
Sie müssen nicht einmal ersetzen RecyclerView in deinem Code mit FixedRecyclerView, das Ersetzen des XML-Tags würde ausreichen! (Das stellt sicher, dass der Übergang nach Abschluss von RecyclerView schnell und einfach ist.)
Erläuterung:
Grundsätzlich, canScrollVertically(boolean) gibt false zu früh zurück, also prüfen wir, ob die RecyclerView wird ganz nach oben in der ersten Ansicht gescrollt (wo die Spitze des ersten untergeordneten Elements 0 wäre) und dann zurückkehrt.
EDIT: Und wenn Sie nicht verlängern möchten RecyclerView Aus irgendeinem Grund können Sie verlängern SwipeRefreshLayout und überschreiben die canChildScrollUp() -Methode und fügen Sie dort die Prüflogik ein.
EDIT2: RecyclerView wurde veröffentlicht und bisher besteht keine Notwendigkeit, diesen Fix zu verwenden.
Ich habe den Code aktualisiert, um einen Fall zu beheben, in dem der Adapter 0 für getCount() zurückgibt
– tom91136
11. August 2014 um 14:56 Uhr
Ich denke, es sollte sein: if (direction < 0)
– Cybergen
3. September 2014 um 8:22 Uhr
Das sagst du also canScrollVertically wird nirgendwo überhaupt angerufen? Dann verwenden Sie möglicherweise immer noch die Bibliotheksversion von RecyclerView. Fügen Sie einige hinzu Log zum Konstruktor und sehen, ob das überhaupt aufgerufen wird.
– tom91136
28. Dezember 2014 um 0:32 Uhr
Ich sah dasselbe wie @Marky17, die Methode wurde nicht aufgerufen. Nach dem Graben war der Grund, dass mein FixedRecyclerView (FRV) kein DIREKTER Nachkomme des SwipeRefreshLayout (SRL) war. Mein FRV befand sich in einem FrameLayout (damit ich eine QuickReturn-Leiste hinzufügen konnte). Als SRL also versuchte, sein Kind “CanScrollVertically?” Es wurde das umschließende FrameLayout abgefragt, nicht das FRV. Ihr Ansatz funktioniert perfekt, wenn das FRV das (einzige?) direkte Kind des SRL ist. Für meine App habe ich SRL optimiert, um nach einem FRV-Kind zu suchen, wenn es auf ein FrameLayout trifft. Vielen Dank!
– MojoTosh
2. Januar 2015 um 17:39 Uhr
Nur um dies hinzuzufügen, wenn Ihre Recycler-Ansicht oben eine Auffüllung für ein schnelles Rückkehr-Symbolleistenmuster hinzugefügt hat, müssen wir dies berücksichtigen, indem wir getChildAt(0).getTop() < 0 in getChildAt(0).getTop() < getPaddingTop ändern ()
– Steve G.
3. Februar 2015 um 20:13 Uhr
Balachandarkm
Ich bin vor kurzem auf das gleiche Problem gestoßen. Ich habe den von @Krunal_Patel vorgeschlagenen Ansatz ausprobiert, aber er hat die meiste Zeit in meinem Nexus 4 funktioniert und in Samsung Galaxy S2 überhaupt nicht funktioniert. Beim Debuggen ist recyclerView.getChildAt(0).getTop() immer nicht korrekt für RecyclerView. Nachdem ich verschiedene Methoden durchgegangen war, dachte ich mir, dass wir die Methode findFirstCompletelyVisibleItemPosition() des LayoutManagers verwenden können, um vorherzusagen, ob das erste Element der RecyclerView sichtbar ist oder nicht, um SwipeRefreshLayout zu aktivieren. Finden Sie den folgenden Code. Hoffe, es hilft jemandem, der versucht, das gleiche Problem zu beheben. Prost.
recyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() {
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
}
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
swipeRefresh.setEnabled(linearLayoutManager.findFirstCompletelyVisibleItemPosition() == 0);
}
});
Obwohl ich mit der Verwendung eines Scroll-Listeners nicht einverstanden bin, habe ich dieselbe Bedingung verwendet, um die zu überschreiben SwipeRefreshLayout‘s canChildScrollUp Methode und es scheint gut zu funktionieren.
– verdammter Maurer
26. November 2014 um 11:55 Uhr
Version 21.0.2 von AppCompat hat in meinem Fall die Notwendigkeit einer Problemumgehung beseitigt
– verdammter Maurer
8. Februar 2015 um 12:44 Uhr
@darnmason Gut zu wissen 🙂
– Balachandarkm
8. Februar 2015 um 12:56 Uhr
@darnmason Ich habe es mit 21.0.2 versucht. Aber bei mir ist es immer noch so. Es hat nicht funktioniert.
– Balachandarkm
25. Februar 2015 um 11:37 Uhr
linearLayoutManager.findFirstCompletelyVisibleItemPosition() gibt bei mir immer null zurück!
– Saravanabalagi Ramachandran
9. April 2016 um 16:16 Uhr
Amrut Bidri
So habe ich dieses Problem in meinem Fall gelöst. Es könnte für jemanden nützlich sein, der hier landet, um nach ähnlichen Lösungen zu suchen.
recyclerView.addOnScrollListener(new OnScrollListener()
{
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy)
{
// TODO Auto-generated method stub
super.onScrolled(recyclerView, dx, dy);
}
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState)
{
// TODO Auto-generated method stub
//super.onScrollStateChanged(recyclerView, newState);
int firstPos=linearLayoutManager.findFirstCompletelyVisibleItemPosition();
if (firstPos>0)
{
swipeLayout.setEnabled(false);
}
else {
swipeLayout.setEnabled(true);
}
}
});
Ich hoffe, dies könnte definitiv jemandem helfen, der nach einer ähnlichen Lösung sucht.
recyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() {
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
}
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
swipeRefresh.setEnabled(linearLayoutManager.findFirstCompletelyVisibleItemPosition() == 0);
}
});
Bitte erwägen Sie die Verwendung eines Open-Source-Dateihostingdienstes (z. B. GitHub oder BitBucket), anstatt Ihr gesamtes Projekt zu komprimieren und auf Google Drive hochzuladen.
– Edric
10. Dezember 2018 um 6:59 Uhr
Maria Rodionova
Keine der Antworten hat bei mir funktioniert, aber ich habe es geschafft, meine eigene Lösung zu implementieren, indem ich eine benutzerdefinierte Implementierung von LinearLayoutManager erstellt habe. Poste es hier, falls jemand anderes es braucht.
class LayoutManagerScrollFixed(context: Context) : LinearLayoutManager(context) {
override fun smoothScrollToPosition(
recyclerView: RecyclerView?,
state: RecyclerView.State?,
position: Int
) {
super.smoothScrollToPosition(recyclerView, state, position)
val child = getChildAt(0)
if (position == 0 && recyclerView != null && child != null) {
scrollVerticallyBy(child.top - recyclerView.paddingTop, recyclerView.Recycler(), state)
}
}
Bitte erwägen Sie die Verwendung eines Open-Source-Dateihostingdienstes (z. B. GitHub oder BitBucket), anstatt Ihr gesamtes Projekt zu komprimieren und auf Google Drive hochzuladen.
– Edric
10. Dezember 2018 um 6:59 Uhr
jagit
Leider ist dies ein bekannter Fehler in LinearLayoutManager. Es berechnetScrollOffset nicht richtig, wenn das erste Element sichtbar ist. wird behoben, wenn es veröffentlicht wird.
Dies scheint nicht behoben worden zu sein
– verdammter Maurer
26. November 2014 um 11:06 Uhr
Ich habe eine Beispiel-App erstellt und funktioniert einwandfrei. Können Sie eine Beispiel-App und einen Fehlerbericht auf b.android.com erstellen? Vielen Dank.
– jagit
1. Dezember 2014 um 19:03 Uhr
Mein Layout ist ziemlich komplex und als ich versuchte, das Problem in einer Beispiel-App zu reproduzieren, stellte ich fest, dass es eine Nebenversion 21.0.2 von AppCompat gab, die es behoben hat. 😀
– verdammter Maurer
2. Dezember 2014 um 12:22 Uhr
Das sind tolle Neuigkeiten, danke fürs Prüfen. Ich empfehle Ihnen dringend, auch Ihr Hauptprojekt zu aktualisieren, da es auch andere Fehlerbehebungen gibt.
– jagit
2. Dezember 2014 um 16:51 Uhr
12158200cookie-checkRecyclerView und SwipeRefreshLayoutyes
Ich hatte genau das gleiche Problem. Außerdem ist mir aufgefallen, dass RecyclerView von getScrollY() immer 0 zurückgibt. Vielleicht ist dies logisch, da verschiedene LayoutManager ausgetauscht werden können, nicht unbedingt scrollende. Ich bin mir nicht sicher, weil ich nicht weiter recherchiert habe. Ich freue mich, eine Lösung zu finden, werde die Antwort aber positiv bewerten, wenn ich sie nach meinem Urlaub in zwei Wochen testen kann.
– Cybergen
14. August 2014 um 18:10 Uhr
Lukas Olsen, dass “texturiert” unglaublich aussieht.
– Jared Burrows
29. Oktober 2014 um 3:06 Uhr