跳到内容
CrossFly 是 100% 开源在 GitHub 关注我们
CrossFlyCrossFly
开始使用

本页面由葡萄牙语机器翻译,可能存在错误。葡萄牙语版本为准。

如何实现加载更多(无限滚动)

目的。 在用户接近列表末尾时自动加载更多数据,将项目追加到现有数据集(append)。 与带 LRU 缓存的分页(paginacao.md)不同,这里由你控制数据集, 列表仅在需要获取更多数据时发出通知。

使用的 API

  • VirtualListView.onLoadMore(Runnable callback) — 当滚动接近末尾时触发。每次只有一个待处理的触发(loadMorePending),避免重复调用。
  • VirtualListView.loadMoreThreshold(int threshold) — 距离末尾多少项时触发回调。默认 5。
  • VirtualListView.notifyDataChanged() — 在追加新项后必须调用;它会清除 loadMorePending、隐藏加载指示器并重新测量内容。

完整示例(复制、粘贴并运行)

package com.exemplo;

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

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

/** 可执行的主界面。将 launcher 指向此类(classname)并运行:gradlew :lwjgl3:run */
public class MainWindow extends Window
{
   final List<String> dados = new ArrayList<>();
   int proxima = 0;

   /** 向数据集追加一批 30 个项目(模拟服务器返回的一页)。 */
   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();   // 填充第一批

      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);   // 在末尾前 8 项开始拉取(默认为 5)
      lista.onLoadMore(() ->
      {
         // 接近末尾时触发一次;后续触发仅在 notifyDataChanged 之后
         onUI(() ->
         {
            carregarPagina();             // 追加(新索引在末尾)
            lista.notifyDataChanged();    // 放行下一次 load-more 并隐藏 spinner
         });
      });

      add(LAY_FILL, lista);
   }
}

下面的片段只展示核心部分。要运行它,请将其放入上面的 MainWindow 骨架中。

最小片段

// 已在源码核实:VirtualListView.java(onLoadMore / loadMoreThreshold / notifyDataChanged)
final Array<String> dados = new Array<>();
carregarPagina(dados, 0);   // 填充第一批

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);   // 在末尾前 8 项开始拉取(默认为 5)
lista.onLoadMore(() ->
{
   // 接近末尾时触发一次;后续触发仅在 notifyDataChanged 之后
   api.proximaPagina(novos ->
   {
      dados.addAll(novos);          // 追加(新索引在末尾)
      lista.notifyDataChanged();    // 放行下一次 load-more 并隐藏 spinner
   });
});

layout.add(1f, lista);

深入了解

  • VirtualListView 在加载更多处于待处理状态时会自动在底部显示加载指示器(由 VirtualListViewStyle.showSpinner 控制)。
  • 如果你不调用 notifyDataChanged(),loadMorePending 将卡在 true,回调将永远不再触发。
  • 需要带有限缓存的可丢弃页面(而非无限追加)?使用 paginacao.md。
  • 组件指南:VirtualListView · 姊妹配方:lista-virtual-grande.md · 权威来源:第 15 章
这个页面有帮助吗?