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

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

ListView

ListView 是一个可滚动的文本项选择列表,可随时嵌入任意容器。每一项都会变成一个可点击的“卡片”。选择模式在构造函数中通过 ItemType 固定:SINGLE(点击即选择并确认)或 MULTIPLE(复选框 + “确认”按钮)。

与 VirtualListView 不同,ListView 为每一项创建一个组件(不回收)—— 适合小/中型列表(数十项),而不适合数千行。

🟡 · 包: dev.crossfly.ui · 继承自: Component · 样式: ListViewStyle(项/表头/按钮)+ WindowStyle(背景,通过 selectionWindowStyle())

何时使用

  • 屏幕内嵌入的选择器(选项菜单、筛选器、类别选择)。
  • 数十个文本项,且无需滚动的精确高度很有用(computeIdealHeight)。
  • 需要显式确认的多选(MULTIPLE)。

何时不要使用

  • 大型列表(数百/数千项)→ 使用会回收组件的 VirtualListView。
  • 模态弹出选择 → 使用 ListViewWindow,它将 ListView 包裹在 Window 中。
  • 带图片/多字段的丰富行 → 使用 itemFactory(...) 或用列表项手动构建列表。

外观

居中文本卡片的垂直列(column),带可选表头(标题 + 返回图标),在 MULTIPLE 模式下底部还有一个“确认”按钮。在 SINGLE 模式下每个卡片是 LabelItem;在 MULTIPLE 模式下是 CheckLabelItem(复选框 + 标签)。

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

package com.exemplo;

import dev.crossfly.ui.*;
import dev.crossfly.ui.layout.*;

/** 可执行的主界面。将 launcher 指向此类(classname)并运行:gradlew :lwjgl3:run */
public class MainWindow extends Window
{
   @Override
   public void onShow() throws Exception
   {
      super.onShow();
      setLayout(new VerticalLayout());

      ListView list = new ListView(new String[]{"Um", "Dois", "Três"}, ListView.ItemType.SINGLE)
         .showHeader(false);
      list.onConfirm(e -> System.out.println("Escolhido: " + list.getSelectedText()));

      add(LAY_FILL, list);   // 列表使用 LAY_FILL(占满高度)
   }
}

下面的片段只展示核心部分(放在 onShow() 里的内容)。要运行它们,请放入上面的 MainWindow 骨架中。

基本用法

// SINGLE,无表头,自动高度(不滚动)
ListView list = new ListView(new String[]{"Um", "Dois", "Três"}, ListView.ItemType.SINGLE)
   .showHeader(false);
list.onConfirm(e -> System.out.println("Escolhido: " + list.getSelectedText()));
contents.add(.95f, list);

构造函数

构造函数 描述
ListView(String[] items, ItemType itemType) 无标题列表
ListView(String title, String[] items, ItemType itemType) 表头带标题的列表

ItemType(定义于 UIConstants):SINGLE 或 MULTIPLE。构造之后该模式不可变。

属性与自定义

属性 / 方法 类型 默认值 作用
addItem(String) ListView — 添加一项(惰性重建;忽略 null)
addItems(String...) ListView — 添加多项(仅一次失效)
showHeader(boolean) ListView true 显示/隐藏表头(标题 + 返回)
title(String) ListView null 设置标题
confirmText(String) ListView "Confirmar" 按钮文本(仅 MULTIPLE)
itemStyle(ComponentStyle) ListView 主题 覆盖所有项的样式
confirmButtonStyle(ComponentStyle) ListView 主题 确认按钮的样式
headerStyle(LabelStyle) ListView 主题 表头样式
itemFactory(ItemFactory) ListView null 自定义项工厂(接收 text、index)
closeAction(Runnable) ListView null 关闭动作(ListViewWindow 将其指向 this::hide)
computeIdealHeight(int width) int — 无滚动的精确高度,若存在 itemFactory 则返回 -1

选择查询

getSelectedCount()、getSelectedIndex()、getSelectedText()、getSelectedIndices()、getSelectedTexts()、isSelected(int)、getSelectionState()(boolean[])。

回调与事件

回调 触发时机
onConfirm(Component.Action) SINGLE:点击某项时。MULTIPLE:点击“确认”时

在 SINGLE 模式下,点击会清除之前的选择、标记该索引、触发 onConfirm 并调用 close()。在 MULTIPLE 模式下,点击会切换该项的复选框;确认由按钮发出。

状态

  • SINGLE —— 一次只标记一项;点击即确认并关闭。
  • MULTIPLE —— 可标记多项;即使在确认前也可通过 getSelectionState() 查询状态。
  • 表头和底部按钮是可选的(取决于 showHeader/title 和 ItemType)。

带自动高度的 MULTIPLE

ListView multi = new ListView(new String[]{"Vermelho", "Verde", "Azul"},
      ListView.ItemType.MULTIPLE)
   .showHeader(false)
   .confirmText("Aplicar");
multi.getStyle().autoHeight(Relative.ofFont(9f));
multi.onConfirm(e -> {
   for (String t : multi.getSelectedTexts())
      System.out.println("marcado: " + t);
});
contents.add(.95f, multi);

使用 itemFactory 的自定义行

ListView list = new ListView(labels, ListView.ItemType.SINGLE).showHeader(false);
list.itemFactory((text, index) -> {
   Component row = new Component();
   row.style(Styles.component().pressable().ingap(Gap.ofFont(.3f)));
   row.setLayout(new GridLayout(Position.START, Position.CENTER));
   row.add(new Label(text));
   return row;
});
list.onConfirm(e -> System.out.println("idx = " + list.getSelectedIndex()));
contents.add(.95f, list);

最佳实践

  • 优先使用 addItems(...) 而不是多次 addItem(...) —— 只触发一次布局失效。
  • 当你想要一个无滚动且高度精确的列表时使用 computeIdealHeight(width)(若存在 itemFactory 则返回 -1,因为自定义项无法被通用地度量)。
  • 项的重建是惰性的(发生在下一次布局时),包括宽度变化时。

常见错误

  • 将 ListView 用于数千项 —— 它不回收;内存呈线性增长。请迁移到 VirtualListView。
  • 期望 MULTIPLE 每次点击都触发 onConfirm —— 在 MULTIPLE 模式下回调仅在按钮“确认”时触发;用 getSelectionState() 来响应每次标记。
  • 假设存在无项的构造函数 —— 构造函数要求提供 items 和 ItemType;请以 new String[]{} 起步并使用 addItems(...)。

另请参阅

这个页面有帮助吗?