gridLayout 表格布局
gridLayout 组件将内部的子组件布局在一个响应式、二维的表格系统中,基于 CSS 的 Grid 布局。
XML 元素 |
|
|---|---|
Java 类 |
|
XML 属性 |
id - alignSelf - classNames - columnMinWidth - css - enabled - gap - height - itemsContainer - itemsEnum - justifySelf - maxHeight - maxWidth - minHeight - minWidth - visible - width |
事件和处理器 |
|
XML 内部元素 |
基本用法
支持声明式在 XML 中将组件添加至 gridLayout,也支持是编程式通过调用 gridLayout.add() 在控制器添加组件。
声明式添加的示例:
<gridLayout id="gridLayout" width="100%">
<textField placeholder="City" label="Where from?"/>
<textField placeholder="City" label="Where to?"/>
<datePicker label="Depart"/>
<datePicker label="Return"/>
<button text="Search tickets" height="AUTO"/>
</gridLayout>
在视图控制器添加组件的示例:
@ViewComponent
private GridLayout<Object> gridLayout;
@Autowired
private UiComponents uiComponents;
@Subscribe
public void onInit(final InitEvent event) {
Checkbox checkbox = uiComponents.create(Checkbox.class);
checkbox.setLabel("I verify that all information is accurate");
checkbox.setValue(false);
gridLayout.add(checkbox);
}
数据绑定
数据绑定是指将组件与 数据容器 进行关联。
在 gridLayout 组件中,将 itemsContainer 属性设置为数据容器实现数据绑定。
<data>
<collection id="usersDc" class="com.company.onboarding.entity.User"> (1)
<fetchPlan extends="_base">
<property name="department" fetchPlan="_base"/>
</fetchPlan>
<loader id="usersDl" readOnly="true">
<query>
<![CDATA[select e from User e]]>
</query>
</loader>
</collection>
</data>
<facets>
<dataLoadCoordinator auto="true"/> (2)
</facets>
<layout>
<gridLayout width="100%"
itemsContainer="usersDc"/> (3)
</layout>
| 1 | 保存 User 实例集合的数据容器。 |
| 2 | 数据加载协调器,自动为组件提供要显示的实例。 |
| 3 | 指定包含要显示的条目列表的容器。 |
默认情况下,组件显示实体的 实例名称。
| 可以通过配置 自定义渲染器 来修改显示内容。 |
该组件还支持使用 itemsEnum 属性显示枚举值。
<gridLayout itemsEnum="com.company.onboarding.entity.DayOfWeek"
width="100%"/>
条目渲染
可以自定义条目的渲染方式。渲染器对每个条目有效,创建一个表示该条目的组件。
可以通过两种不同的方法实现自定义渲染。
编程方式
在视图控制器中,可以使用以下任一方式:
-
setRenderer()方法; -
@Supply注解。
Show code
@Supply(to = "gridLtUsers", subject = "renderer")
private ComponentRenderer<Card, User> gridLtUsersRenderer() { (1)
return new ComponentRenderer<>(this::createCard, this::initCard);
}
private Card createCard() { (2)
Card card = uiComponents.create(Card.class);
card.setWidthFull();
card.addThemeVariants(CardVariant.LUMO_OUTLINED, CardVariant.LUMO_ELEVATED);
return card;
}
private void initCard(Card card, User user) { (3)
card.setHeaderPrefix(createAvatar(user));
card.setTitle(user.getFirstName() + " " + user.getLastName());
card.setSubtitle(createSubtitle(user));
card.setHeaderSuffix(createHeaderSuffix(user));
}
private Image createAvatar(User user) { (4)
Image image = uiComponents.create(Image.class);
FileRef fileRef = user.getPicture();
if (fileRef != null) {
image.setWidth("50px");
image.setHeight("50px");
InputStreamDownloadHandler handler = DownloadHandler.fromInputStream(event -> {
InputStream inputStream = fileStorageLocator.getByName(fileRef.getStorageName()).openStream(fileRef);
return new DownloadResponse(inputStream, fileRef.getFileName(), fileRef.getContentType(), -1);
});
image.setSrc(handler);
}
return image;
}
private Span createSubtitle(User user) {
Span span = uiComponents.create(Span.class);
span.setText("%s: %s".formatted(
getPropertyCaption(user, "department"),
(user.getDepartment() != null ?
user.getDepartment().getName() :
"Not assigned")));
return span;
}
private String getPropertyCaption(User user, String property) {
MetaClass metaClass = metadata.getClass(user);
return messageTools.getPropertyCaption(metaClass, property);
}
private Span createHeaderSuffix(User user) {
Span span = uiComponents.create(Span.class);
if (user.getActive()) {
span.setText("Active");
span.getElement().getThemeList().add("badge success");
}
else {
span.setText("Inactive");
span.getElement().getThemeList().add("badge error");
}
return span;
}
| 1 | 自定义渲染器,将每个 User 显示为 Card。 |
| 2 | 创建一个带有通用样式的基本 Card 组件。 |
| 3 | 使用用户特定数据初始化卡片内容。为每个卡片实例调用,并传入对应的 User 实体。 |
| 4 | 从用户的图片创建一个头像 图片 组件。 |
声明式方式
或者,可以使用嵌套的 fragmentRenderer 元素来渲染项目。
-
创建
FragmentRendererXML:<?xml version="1.0" encoding="UTF-8" standalone="no"?> <fragment xmlns="http://jmix.io/schema/flowui/fragment"> <data> <instance id="userDc" class="com.company.onboarding.entity.User"> <loader id="userDl"/> <fetchPlan extends="_base"/> </instance> </data> <content> <vbox id="root" padding="false"/> </content> </fragment> -
创建
FragmentRendererJava 控制器fragment 渲染器类应继承
FragmentRenderer基类,并使用类型参数设置根组件的类型和渲染的实体,例如:Show code
@FragmentDescriptor("card-fragment.xml") @RendererItemContainer("userDc") public class CardFragment extends FragmentRenderer<VerticalLayout, User> { @Autowired private FileStorageLocator fileStorageLocator; @Autowired private Metadata metadata; @Autowired private MessageTools messageTools; @Override protected void onAttach(AttachEvent attachEvent) { super.onAttach(attachEvent); initLayout(); } private void initLayout() { Card card = uiComponents.create(Card.class); card.setWidthFull(); card.addThemeVariants(CardVariant.LUMO_OUTLINED, CardVariant.LUMO_ELEVATED); card.setHeaderPrefix(createAvatar(getItem())); card.setTitle(getItem().getFirstName() + " " + getItem().getLastName()); card.setSubtitle(createSubtitle(getItem())); card.setHeaderSuffix(createHeaderSuffix(getItem())); getContent().add(card); } private Image createAvatar(User user) { Image image = uiComponents.create(Image.class); FileRef fileRef = user.getPicture(); if (fileRef != null) { image.setWidth("50px"); image.setHeight("50px"); InputStreamDownloadHandler handler = DownloadHandler.fromInputStream(event -> { InputStream inputStream = fileStorageLocator.getByName(fileRef.getStorageName()).openStream(fileRef); return new DownloadResponse(inputStream, fileRef.getFileName(), fileRef.getContentType(), -1); }); image.setSrc(handler); } return image; } private Span createSubtitle(User user) { Span span = uiComponents.create(Span.class); span.setText("%s: %s".formatted( getPropertyCaption(user, "department"), (user.getDepartment() != null ? user.getDepartment().getName() : "Not assigned"))); return span; } private String getPropertyCaption(User user, String property) { MetaClass metaClass = metadata.getClass(user); return messageTools.getPropertyCaption(metaClass, property); } private Span createHeaderSuffix(User user) { Span span = uiComponents.create(Span.class); if (user.getActive()) { span.setText("Active"); span.getElement().getThemeList().add("badge success"); } else { span.setText("Inactive"); span.getElement().getThemeList().add("badge error"); } return span; } } -
gridLayout组件使用fragmentRenderer:<gridLayout id="gridUsers" width="100%" itemsContainer="usersDc" gap="var(--lumo-space-m)"> <fragmentRenderer class="com.company.onboarding.view.layout.gridlayout.CardFragment"/> </gridLayout>
XML 属性
通用属性 对所有组件都是一样的配置。
下面是 gridLayout 的特殊属性:
名称 |
描述 |
默认值 |
|---|---|---|
控制组件在其网格单元格内沿块轴(列轴)的垂直对齐方式。对应于 CSS 的 align-self 属性。另请参考 alignSelf。 适用于版本 2.7.2+ 的项目。 |
|
|
设置 |
|
|
控制网格单元格之间的间距(行间距和列间距)。该值为 CSS 长度值(例如 |
|
|
控制组件在其网格单元格内沿内轴(行轴)的水平对齐方式。对应于 CSS 的 justify-self 属性。 适用于版本 2.7.2+ 的项目。 |
|