This page was machine-translated from Portuguese and may contain errors. The Portuguese version is canonical.
How to display a virtual list with thousands of items
Purpose. Display tens of thousands of items without creating one Component per row. The
VirtualListView only creates/renders the visible views and recycles those that leave the screen (like
Android’s RecyclerView). All rows have a fixed height (Relative itemHeight).
APIs used
new VirtualListView(Relative itemHeight, DataAdapter adapter)— single constructor; the height is fixed for all rows.interface DataAdapter(nested inVirtualListView), with three methods:int getCount()— total number of items.Component createView() throws Exception— creates a blank view; called only when the recycling pool is empty.void bindView(Component view, int index) throws Exception— populates a view (new or recycled) with the data at the index.
VirtualListView.notifyDataChanged()— call after the dataset grows/changes under new indices (e.g., an appended page). It does not rebind rows already visible.VirtualListView.reloadData()— full reload: discards the view cache, recycles everything, scrolls to the top, and rebinds all visible slots. Use in search/filter/sort (content changes under the same indices).VirtualListView.scrollToIndex(int index)— scrolls to center the index.VirtualListView.getScrollY()— current vertical offset in pixels (useful for a collapsible header).
Complete example (copy, paste and run)
package com.exemplo;
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
{
@Override
public void onShow() throws Exception
{
super.onShow();
setLayout(new VerticalLayout());
final String[] dados = new String[50_000];
for (int i = 0; i < dados.length; i++) dados[i] = "Registro " + i;
Relative alturaItem = Relative.ofFont(3f); // ~3 font heights per row (scales with the UI)
VirtualListView lista = new VirtualListView(alturaItem, new VirtualListView.DataAdapter()
{
public int getCount()
{
return dados.length;
}
public Component createView() throws Exception
{
// reusable "empty" view — NO data here
return new Label("");
}
public void bindView(Component view, int index) throws Exception
{
// populate the recycled view with the current index's data
((Label) view).setText(dados[index]);
}
});
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 (DataAdapter is a nested interface)
final String[] dados = new String[50_000];
for (int i = 0; i < dados.length; i++) dados[i] = "Registro " + i;
Relative alturaItem = Relative.ofFont(3f); // ~3 font heights per row (scales with the UI)
VirtualListView lista = new VirtualListView(alturaItem, new VirtualListView.DataAdapter()
{
public int getCount()
{
return dados.length;
}
public Component createView() throws Exception
{
// reusable "empty" view — NO data here
return new Label("");
}
public void bindView(Component view, int index) throws Exception
{
// populate the recycled view with the current index's data
((Label) view).setText(dados[index]);
}
});
layout.add(1f, lista);
Updating the data:
// Appended more items at the end (new indices) → notifyDataChanged
carregarMaisDados(dados);
lista.notifyDataChanged();
// Applied a filter/search (same index, different content) → reloadData
aplicarFiltro();
lista.reloadData(); // recycles, scrolls back to top and rebinds the visible items
Go deeper
- Critical rule: never keep references to views between binds — they are recycled for other indices.
- Row with several elements (icon + text + value)? Create a custom
Componentwith abind(...)method that stores the sub-references as fields:createView()returnsnew CardTarefa()andbindViewdoes((CardTarefa) view).bind(dados[index])(see Thinking in components). - Server data by page: see paginacao.md (uses
PagedDataAdapter). - Infinite scroll by append: see carregar-mais.md.
- Widget guide: VirtualListView · Best practices: Performance and large lists · Canonical source: Chapter 15
Was this page helpful?Thanks for the feedback!