virtualList 列表
virtualList 由于仅渲染页面中可见的部分,因此可以高效地展示自定义内容的列表,
XML 元素 |
|
|---|---|
Java 类 |
|
基本用法
或者,可以使用内部的 fragmentRenderer 元素来渲染条目。有关详细信息,请参阅 Fragment 渲染器 部分。
下面是用 virtualList 展示列表视图的示例:
XML
<data readOnly="true">
<collection id="customersDc"
class="io.jmix.uisamples.entity.Customer">
<fetchPlan extends="_base"/>
<loader id="customersDl">
<query>
<![CDATA[select e from Customer e]]>
</query>
</loader>
</collection>
</data>
<facets>
<dataLoadCoordinator auto="true"/>
</facets>
<virtualList id="virtualList" width="30em"
itemsContainer="customersDc"
alignSelf="CENTER"/>
Java
@Autowired
protected UiComponents uiComponents;
@Autowired
protected MetadataTools metadataTools;
@Supply(to = "virtualList", subject = "renderer")
protected Renderer<Customer> virtualListRenderer() {
return new ComponentRenderer<>(customer -> {
VerticalLayout infoLayout = createVerticalLayout();
infoLayout.addClassNames("info-layout");
H4 customerName = new H4(customer.getInstanceName());
Badge gradeBadge = createGradeBadge(customer.getGrade());
infoLayout.add(customerName, gradeBadge);
HorizontalLayout infoLine = createHorizontalLayout();
infoLine.setAlignItems(FlexComponent.Alignment.CENTER);
H5 emailLabel = new H5("Email:");
Span email = new Span(customer.getEmail());
infoLine.add(emailLabel, email);
HorizontalLayout infoLine2 = createHorizontalLayout();
H5 ageLabel = new H5("Age:");
Span age = new Span(String.valueOf(customer.getAge()));
infoLine2.add(ageLabel, age);
VerticalLayout additionalInfoLayout = createVerticalLayout();
additionalInfoLayout.add(infoLine, infoLine2);
JmixDetails infoDetails = uiComponents.create(JmixDetails.class);
infoDetails.setSummaryText("Additional information");
infoDetails.add(additionalInfoLayout);
infoLayout.add(infoDetails, new Hr());
return infoLayout;
});
}
protected VerticalLayout createVerticalLayout() {
VerticalLayout layout = uiComponents.create(VerticalLayout.class);
layout.setSpacing(false);
layout.setPadding(false);
return layout;
}
protected HorizontalLayout createHorizontalLayout() {
HorizontalLayout layout = uiComponents.create(HorizontalLayout.class);
layout.setPadding(false);
return layout;
}
protected Badge createGradeBadge(@Nullable CustomerGrade grade) {
Badge gradeBadge = new Badge(metadataTools.format(grade));
if (grade == CustomerGrade.HIGH) {
gradeBadge.addThemeVariants(BadgeVariant.SUCCESS);
} else if (grade == CustomerGrade.PREMIUM) {
gradeBadge.addThemeVariants(BadgeVariant.FILLED);
}
return gradeBadge;
}
virtualList 中的条目可以通过键盘进行选择或遍历。标准的 列表组件操作 不能用于 virtualList。如需使用 CRUD 操作的话,可以自定义。
自定义渲染器
组件的渲染器可以为每个列表条目创建自定义的展示内容。下面的示例将每个枚举值使用一个标签和一个图标按钮显示。
XML
<virtualList id="virtualList" width="15em"
itemsEnum="io.jmix.uisamples.entity.Day"
alignSelf="CENTER"/>
Java
@Autowired
protected UiComponents uiComponents;
@Autowired
protected MetadataTools metadataTools;
@Autowired
protected Notifications notifications;
@Supply(to = "virtualList", subject = "renderer")
protected Renderer<Day> virtualListRenderer() {
return new ComponentRenderer<>(this::createDayRenderer);
}
protected HorizontalLayout createDayRenderer(Day day) {
HorizontalLayout layout = uiComponents.create(HorizontalLayout.class);
layout.setPadding(false);
String dayValue = metadataTools.format(day);
H3 label = new H3(dayValue);
JmixButton button = uiComponents.create(JmixButton.class);
button.addThemeVariants(ButtonVariant.LUMO_ICON);
button.addClassName(StyleUtility.Button.LINK_BUTTON);
button.addClickListener(__ -> showNotification(dayValue));
Icon icon = switch (day) {
case MONDAY -> VaadinIcon.BRIEFCASE.create();
case TUESDAY -> VaadinIcon.LINE_CHART.create();
case WEDNESDAY -> VaadinIcon.TROPHY.create();
case THURSDAY -> VaadinIcon.GROUP.create();
case FRIDAY -> VaadinIcon.CASH.create();
case SATURDAY -> VaadinIcon.GLASS.create();
case SUNDAY -> VaadinIcon.BED.create();
};
button.setIcon(icon);
layout.add(button, label);
return layout;
}
protected void showNotification(String dayValue) {
String message = String.format("You've clicked on %s!", StringUtils.capitalize(dayValue));
notifications.show(message);
}
行内编辑
结合组件渲染器、数据容器和详情视图弹窗的功能可以在无需单独的表格的情况下创建和编辑列表项。
XML
<data>
<collection id="foodDc" class="io.jmix.uisamples.entity.Food">
<loader id="foodDl"/>
</collection>
</data>
<hbox width="100%" padding="false" alignItems="CENTER">
<h2 id="menusItemsTabTitle" text="msg://foodListTitle"/>
<button id="addBtn"
classNames="virtual-list-inline-editor-add-button"
themeNames="primary"
icon="PLUS"
text="msg:///actions.Add"/>
</hbox>
<html id="foodDescription" content="msg://foodListDescription"/>
<virtualList id="foodList" itemsContainer="foodDc" width="100%"/>
Java
@Autowired
private Messages messages;
@Autowired
private DialogWindows dialogWindows;
@ViewComponent
private DataContext dataContext;
@ViewComponent
private CollectionContainer<Food> foodDc;
@Supply(to = "foodList", subject = "renderer")
public Renderer<Food> foodListRenderer() {
return new ComponentRenderer<>(item -> {
HorizontalLayout rootCardLayout = new HorizontalLayout();
rootCardLayout.setMargin(true);
VerticalLayout infoLayout = new VerticalLayout();
infoLayout.setSpacing(false);
infoLayout.setPadding(false);
infoLayout.setWidth("30%");
Avatar avatar = new Avatar();
avatar.addThemeVariants(AvatarVariant.XLARGE);
if (item.getIcon() != null && item.getIcon().length > 0) {
String iconFileName = "%s.png".formatted(item.getTitle());
InputStreamDownloadHandler handler = DownloadHandler.fromInputStream(event -> {
byte[] icon = item.getIcon();
ByteArrayInputStream inputStream = new ByteArrayInputStream(item.getIcon());
return new DownloadResponse(inputStream, iconFileName, "image/png", icon.length);
});
avatar.setImageHandler(handler);
}
VerticalLayout verticalLayout = new VerticalLayout();
verticalLayout.setWidthFull();
HorizontalLayout itemDetailLayout = new HorizontalLayout();
itemDetailLayout.add(new Text(item.getDescription()));
itemDetailLayout.add(new Html(
messages.formatMessage(getClass(), "foodListItemDescription", item.getPrice()))
);
itemDetailLayout.setPadding(false);
itemDetailLayout.setAlignItems(FlexComponent.Alignment.CENTER);
infoLayout.add(new Html(messages.formatMessage(getClass(), "foodItemTitle", item.getTitle())));
infoLayout.add(itemDetailLayout);
VerticalLayout buttonsPanel = new VerticalLayout();
buttonsPanel.setWidth("AUTO");
buttonsPanel.setPadding(false);
buttonsPanel.setSpacing(false);
Button detailButton = new Button(new Icon(VaadinIcon.PENCIL));
detailButton.setText(messages.getMessage("actions.Edit"));
detailButton.addClickListener(e -> dialogWindows.detail(this, Food.class)
.withViewClass(FoodDetailView.class)
.editEntity(item)
.withAfterCloseListener(closeEvent -> {
if (closeEvent.closedWith(StandardOutcome.SAVE)) {
foodDc.replaceItem(closeEvent.getSource().getView().getEditedEntity());
}
})
.open());
detailButton.addClassName(StyleUtility.Button.LINK_BUTTON);
Button removeButton = new Button(new Icon(VaadinIcon.TRASH));
removeButton.setText(messages.getMessage("actions.Remove"));
removeButton.addThemeVariants(ButtonVariant.ERROR);
removeButton.addClassName(StyleUtility.Button.LINK_BUTTON);
removeButton.addClickListener(e -> {
foodDc.getMutableItems().remove(item);
dataContext.remove(dataContext.merge(item));
});
buttonsPanel.add(detailButton, removeButton);
rootCardLayout.add(avatar, infoLayout, buttonsPanel);
return rootCardLayout;
});
}
@Subscribe(id = "addBtn", subject = "clickListener")
public void onAddBtnClick(final ClickEvent<JmixButton> event) {
dialogWindows.detail(this, Food.class)
.withViewClass(FoodDetailView.class)
.newEntity()
.withAfterCloseListener(closeEvent -> {
if (closeEvent.closedWith(StandardOutcome.SAVE)) {
foodDc.replaceItem(closeEvent.getSource().getView().getEditedEntity());
}
})
.open();
}
事件和处理器
下面是 virtualList 的特殊事件和处理器:
| 名称 | 描述 |
|---|---|
列表条目的自定义渲染器,只能通过 Java 代码在视图控制器中设置。 |
|
如果只需展示纯文本内容,可以用 |
下面是 virtualList 支持的其他通用事件:
本页是否有帮助?
感谢您的反馈