381 Stimmen

Wie implementiere ich eine endlose Liste mit RecyclerView?

Ich möchte ListView in RecyclerView ändern. Ich möchte das onScroll des OnScrollListener in RecyclerView verwenden, um festzustellen, ob ein Benutzer ans Ende der Liste gescrollt ist.

Wie kann ich feststellen, ob ein Benutzer ans Ende der Liste gescrollt ist, damit ich neue Daten von einem REST-Dienst abrufen kann?

473voto

Abdulaziz Noor Punkte 6271

Danke an @Kushal und so habe ich es implementiert

private boolean loading = true;
int pastVisiblesItems, visibleItemCount, totalItemCount;

mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
    @Override
    public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
        if (dy > 0) { // Überprüfen auf nach unten scrollen
            visibleItemCount = mLayoutManager.getChildCount();
            totalItemCount = mLayoutManager.getItemCount();
            pastVisiblesItems = mLayoutManager.findFirstVisibleItemPosition();

            if (loading) {
                if ((visibleItemCount + pastVisiblesItems) >= totalItemCount) {
                    loading = false;
                    Log.v("...", "Letztes Element Wow !");
                    // Pagination durchführen.. d.h. neue Daten abrufen

                    loading = true;
                }
            }
        }
    }
});

Vergessen Sie nicht hinzuzufügen

LinearLayoutManager mLayoutManager;
mLayoutManager = new LinearLayoutManager(this);
mRecyclerView.setLayoutManager(mLayoutManager);

177voto

Kushal Sharma Punkte 5988

Machen Sie diese Variablen.

private int previousTotal = 0;
private boolean loading = true;
private int visibleThreshold = 5;
int firstVisibleItem, visibleItemCount, totalItemCount;

Auf Scrollen für Recycleransicht einstellen.

mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {

    @Override
    public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
        super.onScrolled(recyclerView, dx, dy);

        visibleItemCount = mRecyclerView.getChildCount();
        totalItemCount = mLayoutManager.getItemCount();
        firstVisibleItem = mLayoutManager.findFirstVisibleItemPosition();

        if (loading) {
            if (totalItemCount > previousTotal) {
                loading = false;
                previousTotal = totalItemCount;
            }
        }
        if (!loading && (totalItemCount - visibleItemCount) 
            <= (firstVisibleItem + visibleThreshold)) {
            // Das Ende wurde erreicht

            Log.i("Yaeye!", "Ende aufgerufen");

            // Etwas machen

            loading = true;
        }
    }
});

Hinweis : Stellen Sie sicher, dass Sie LinearLayoutManager als Layout-Manager für RecyclerView verwenden.

LinearLayoutManager mLayoutManager;
mLayoutManager = new LinearLayoutManager(this);
mRecyclerView.setLayoutManager(mLayoutManager);

und für ein Raster

GridLayoutManager mLayoutManager;
mLayoutManager = new GridLayoutManager(getActivity(), spanCount);
mRecyclerView.setLayoutManager(mLayoutManager);

Viel Spaß mit Ihren endlosen Scrolls !! ^.^

Aktualisierung : mRecyclerView.setOnScrollListener() ist veraltet, ersetzen Sie es einfach durch mRecyclerView.addOnScrollListener() und die Warnung wird verschwinden! Weitere Informationen finden Sie unter dieser SO-Frage.

Da Android jetzt offiziell Kotlin unterstützt, hier ein Update für dasselbe -

Erstellen Sie einen OnScrollListener

class OnScrollListener(val layoutManager: LinearLayoutManager, val adapter: RecyclerView.Adapter, val dataList: MutableList) : RecyclerView.OnScrollListener() {
    var previousTotal = 0
    var loading = true
    val visibleThreshold = 10
    var firstVisibleItem = 0
    var visibleItemCount = 0
    var totalItemCount = 0

    override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
        super.onScrolled(recyclerView, dx, dy)

        visibleItemCount = recyclerView.childCount
        totalItemCount = layoutManager.itemCount
        firstVisibleItem = layoutManager.findFirstVisibleItemPosition()

        if (loading) {
            if (totalItemCount > previousTotal) {
                loading = false
                previousTotal = totalItemCount
            }
        }

        if (!loading && (totalItemCount - visibleItemCount) <= (firstVisibleItem + visibleThreshold)) {
            val initialSize = dataList.size
            updateDataList(dataList)
            val updatedSize = dataList.size
            recyclerView.post { adapter.notifyItemRangeInserted(initialSize, updatedSize) }
            loading = true
        }
    }
}

und fügen Sie es Ihrem RecyclerView wie folgt hinzu

recyclerView.addOnScrollListener(OnScrollListener(layoutManager, adapter, dataList))

Für ein vollständiges Codebeispiel können Sie gerne auf dieses Github-Repository verweisen.

79voto

Hai Zhang Punkte 5356

Für diejenigen, die nur benachrichtigt werden möchten, wenn der letzte Artikel vollständig angezeigt wird, können Sie View.canScrollVertically() verwenden.

Hier ist meine Implementierung:

public abstract class OnVerticalScrollListener
        extends RecyclerView.OnScrollListener {

    @Override
    public final void onScrolled(RecyclerView recyclerView, int dx, int dy) {
        if (!recyclerView.canScrollVertically(-1)) {
            onScrolledToTop();
        } else if (!recyclerView.canScrollVertically(1)) {
            onScrolledToBottom();
        } else if (dy < 0) {
            onScrolledUp();
        } else if (dy > 0) {
            onScrolledDown();
        }
    }

    public void onScrolledUp() {}

    public void onScrolledDown() {}

    public void onScrolledToTop() {}

    public void onScrolledToBottom() {}
}

Hinweis: Sie können recyclerView.getLayoutManager().canScrollVertically() verwenden, wenn Sie API < 14 unterstützen möchten.

75voto

Sabeer Punkte 3800

Hier ist ein weiterer Ansatz. Es funktioniert mit jedem Layout-Manager.

  1. Machen Sie die Adapterklasse abstrakt
  2. Erstellen Sie dann eine abstrakte Methode in der Adapterklasse (z.B. load())
  3. In onBindViewHolder überprüfen Sie die Position, ob es die letzte ist, und rufen Sie load() auf
  4. Überschreiben Sie die load() Funktion beim Erstellen des Adapterobjekts in Ihrer Aktivität oder Ihrem Fragment.
  5. Implementieren Sie im überladenen load() Funktion Ihr Loadmore-Aufruf.

Für ein detailliertes Verständnis habe ich einen Blogbeitrag und ein Beispielprojekt verfasst, das Sie hier erhalten

MyAdapter.java

public abstract class MyAdapter extends RecyclerView.Adapter{

        @Override
        public void onBindViewHolder(ViewHolder holder, int position) {
            // Überprüfen Sie das letzte Element
            if ((position >= getItemCount() - 1))
                load();
        }

        public abstract void load();
}

MyActivity.java

public class MainActivity extends AppCompatActivity {
    List items;
    MyAdapter adapter;

   @Override
    protected void onCreate(Bundle savedInstanceState) {
    ...
    adapter=new MyAdapter(items){
            @Override
            public void load() {
                // Implementieren Sie hier Ihr Load-More
                Item lastItem=items.get(items.size()-1);
                loadMore();
            }
        };
   }
}

21voto

Federico Ponzi Punkte 2573

Meine Antwort ist eine modifizierte Version von Noor. Ich bin von einem ListView übergegangen, wo ich einen EndlessScrollListener hatte (den Sie in vielen Antworten auf SO leicht finden können), zu einem RecyclerView, also wollte ich einen EndlessRecyclScrollListener, um meinen bisherigen Listener einfach zu aktualisieren.

Hier ist der Code, ich hoffe er hilft:

public abstract class EndlessScrollRecyclListener extends RecyclerView.OnScrollListener
{
    // Die Gesamtzahl der Elemente im Datensatz nach dem letzten Laden
    private int previousTotalItemCount = 0;
    private boolean loading = true;
    private int visibleThreshold = 5;
    int firstVisibleItem, visibleItemCount, totalItemCount;
    private int startingPageIndex = 0;
    private int currentPage = 0;

    @Override
    public void onScrolled(RecyclerView mRecyclerView, int dx, int dy)
    {
        super.onScrolled(mRecyclerView, dx, dy);
        LinearLayoutManager mLayoutManager = (LinearLayoutManager) mRecyclerView
                .getLayoutManager();

        visibleItemCount = mRecyclerView.getChildCount();
        totalItemCount = mLayoutManager.getItemCount();
        firstVisibleItem = mLayoutManager.findFirstVisibleItemPosition();
        onScroll(firstVisibleItem, visibleItemCount, totalItemCount);
    }

    public void onScroll(int firstVisibleItem, int visibleItemCount, int totalItemCount)
    {
        // Wenn die Gesamtzahl der Elemente null ist und die vorherige nicht, nehmen wir an, dass die
        // Liste ungültig ist und in den ursprünglichen Zustand zurückgesetzt werden sollte
        if (totalItemCount < previousTotalItemCount)
        {
            this.currentPage = this.startingPageIndex;
            this.previousTotalItemCount = totalItemCount;
            if (totalItemCount == 0)
            {
                this.loading = true;
            }
        }
        // Wenn immer noch geladen wird, prüfen wir, ob sich die Datensatzanzahl geändert hat,
        // wenn ja, schließen wir daraus, dass das Laden abgeschlossen ist, und aktualisieren die aktuelle Seite
        // und die Gesamtanzahl der Elemente.
        if (loading && (totalItemCount > previousTotalItemCount))
        {
            loading = false;
            previousTotalItemCount = totalItemCount;
            currentPage++;
        }

        // Wenn gerade nicht geladen wird, prüfen wir, ob wir die visibleThreshold überschritten haben
        // und mehr Daten nachladen müssen.
        // Wenn wir mehr Daten nachladen müssen, führen wir onLoadMore aus, um die Daten abzurufen.
        if (!loading && (totalItemCount - visibleItemCount) <= (firstVisibleItem +
                visibleThreshold))
        {
            onLoadMore(currentPage + 1, totalItemCount);
            loading = true;
        }
    }

    // Definiert den Prozess zum Laden weiterer Daten basierend auf der Seitennummer
    public abstract void onLoadMore(int page, int totalItemsCount);

}

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X