This page was machine-translated from Portuguese and may contain errors. The Portuguese version is canonical.
How to implement load-more (infinite scroll)
Purpose. Automatically load more data as the user approaches the end of the list, appending items to the existing dataset (append). Unlike pagination with an LRU cache (paginacao.md), here you control the dataset and the list only signals when it is time to fetch more.
APIs used
VirtualListView.onLoadMore(Runnable callback)— fires when the scroll gets near the end. Only one trigger stays pending at a time (loadMorePending), preventing duplicate calls.VirtualListView.loadMoreThreshold(int threshold)— how many items before the end fire the callback. Default5.VirtualListView.notifyDataChanged()— required to call after appending the new items; it clearsloadMorePending, hides the spinner, and re-measures the content.
Complete example (copy, paste and run)
package com.exemplo;
import java.util.*; // List / ArrayList
import dev.crossfly.ui.*;
import dev.crossfly.ui.layout.*;
import dev.crossfly.ui.graphics.*; // Relative (for VirtualListView)
/** Runnable main screen. Point the launcher (classname) and run: gradlew :lwjgl3:run */
public class MainWindow extends Window
{
final List<String> dados = new ArrayList<>();
int proxima = 0;
/** Appends a batch of 30 items to the dataset (simulates a server page). */
private void carregarPagina()
{
for (int i = 0; i < 30; i++)
dados.add("Registro " + (proxima++));
}
@Override
public void onShow() throws Exception
{
super.onShow();
setLayout(new VerticalLayout());
carregarPagina(); // populates the first batch
VirtualListView lista = new VirtualListView(Relative.ofFont(3f), new VirtualListView.DataAdapter()
{
public int getCount() { return dados.size(); }
public Component createView() { return new Label(""); }
public void bindView(Component v, int i) throws Exception
{
((Label) v).setText(dados.get(i));
}
});
lista.loadMoreThreshold(8); // starts fetching 8 items before the end (default is 5)
lista.onLoadMore(() ->
{
// fires ONCE when nearing the end; further fires only after notifyDataChanged
onUI(() ->
{
carregarPagina(); // APPENDS (new indices at the end)
lista.notifyDataChanged(); // releases the next load-more and hides the spinner
});
});
add(LAY_FILL, lista);
}
}
The snippet below shows only the core. To run it, place it inside the
MainWindowskeleton above.
Minimal snippet
// verified in source: VirtualListView.java (onLoadMore / loadMoreThreshold / notifyDataChanged)
final Array<String> dados = new Array<>();
carregarPagina(dados, 0); // populates the first batch
VirtualListView lista = new VirtualListView(Relative.ofFont(3f), new VirtualListView.DataAdapter()
{
public int getCount() { return dados.size(); }
public Component createView() { return new Label(""); }
public void bindView(Component v, int i) throws Exception
{
((Label) v).setText(dados.get(i));
}
});
lista.loadMoreThreshold(8); // starts fetching 8 items before the end (default is 5)
lista.onLoadMore(() ->
{
// fires ONCE when nearing the end; further fires only after notifyDataChanged
api.proximaPagina(novos ->
{
dados.addAll(novos); // APPENDS (new indices at the end)
lista.notifyDataChanged(); // releases the next load-more and hides the spinner
});
});
layout.add(1f, lista);
Go deeper
- The
VirtualListViewautomatically shows a spinner in the footer while the load-more is pending (controlled byVirtualListViewStyle.showSpinner). - If you do not call
notifyDataChanged(),loadMorePendingstays stuck attrueand the callback never fires again. - Need disposable pages with a bounded cache (instead of infinite append)? Use paginacao.md.
- Widget guide: VirtualListView · Sibling recipe: lista-virtual-grande.md · Canonical source: Chapter 15
Was this page helpful?Thanks for the feedback!