Saltar al contenido
CrossFly es 100% open sourceSíguenos en GitHub
CrossFlyCrossFly
Empezar

Esta página fue traducida automáticamente del portugués y puede contener errores. La versión en portugués es la canónica.

Cómo implementar cargar-más (scroll infinito)

Propósito. Cargar más datos automáticamente a medida que el usuario se acerca al final de la lista, anexando elementos al dataset existente (append). A diferencia de la paginación con caché LRU (paginacao.md), aquí tú controlas el dataset y la lista solo avisa cuándo es hora de buscar más.

APIs usadas

  • VirtualListView.onLoadMore(Runnable callback) — se dispara cuando el scroll llega cerca del final. Solo un disparo a la vez queda pendiente (loadMorePending), evitando llamadas duplicadas.
  • VirtualListView.loadMoreThreshold(int threshold) — cuántos elementos antes del final disparan el callback. Default 5.
  • VirtualListView.notifyDataChanged() — obligatorio llamarlo después de anexar los nuevos elementos; limpia el loadMorePending, oculta el spinner y vuelve a medir el contenido.

Ejemplo completo (copiar, pegar y ejecutar)

package com.exemplo;

import java.util.*;   // List / ArrayList

import dev.crossfly.ui.*;
import dev.crossfly.ui.layout.*;
import dev.crossfly.ui.graphics.*;   // Relative (para VirtualListView)

/** Pantalla principal ejecutable. Apunta el launcher (classname) y corre: gradlew :lwjgl3:run */
public class MainWindow extends Window
{
   final List<String> dados = new ArrayList<>();
   int proxima = 0;

   /** Añade una tanda de 30 ítems al dataset (simula una página del servidor). */
   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();   // puebla la primera tanda

      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);   // empieza a buscar 8 ítems antes del final (default es 5)
      lista.onLoadMore(() ->
      {
         // dispara UNA vez al acercarse al final; próximos disparos solo tras notifyDataChanged
         onUI(() ->
         {
            carregarPagina();             // AÑADE (nuevos índices al final)
            lista.notifyDataChanged();    // libera el próximo load-more y oculta el spinner
         });
      });

      add(LAY_FILL, lista);
   }
}

El fragmento de abajo muestra solo el núcleo. Para ejecutarlo, colócalo en el esqueleto MainWindow de arriba.

Fragmento mínimo

// verificado en la fuente: VirtualListView.java (onLoadMore / loadMoreThreshold / notifyDataChanged)
final Array<String> dados = new Array<>();
carregarPagina(dados, 0);   // puebla la primera tanda

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);   // empieza a buscar 8 ítems antes del final (default es 5)
lista.onLoadMore(() ->
{
   // dispara UNA vez al acercarse al final; próximos disparos solo tras notifyDataChanged
   api.proximaPagina(novos ->
   {
      dados.addAll(novos);          // AÑADE (nuevos índices al final)
      lista.notifyDataChanged();    // libera el próximo load-more y oculta el spinner
   });
});

layout.add(1f, lista);

Profundiza

  • El VirtualListView muestra automáticamente un spinner en el pie mientras el cargar-más está pendiente (controlado por VirtualListViewStyle.showSpinner).
  • Si no llamas a notifyDataChanged(), loadMorePending queda trabado en true y el callback nunca vuelve a dispararse.
  • ¿Necesitas páginas descartables con caché limitada (en lugar de append infinito)? Usa paginacao.md.
  • Guía del widget: VirtualListView · Receta hermana: lista-virtual-grande.md · Fuente canónica: Capítulo 15
¿Te resultó útil esta página?