gridLayout

Компонент gridLayout располагает дочерние компоненты в адаптивной, двумерной системе сетки, основанной на CSS Grid Layout.

XML-элемент

gridLayout

Java-класс

GridLayout

Атрибуты

id - alignSelf - classNames - columnMinWidth - css - enabled - gap - height - itemsContainer - itemsEnum - maxHeight - maxWidth - minHeight - minWidth - visible - width

Обработчики

AttachEvent - itemLabelGenerator - renderer - DetachEvent

Элементы

fragmentRenderer

Основы

Вы можете заполнить gridLayout компонентами либо декларативно в XML-дескрипторе, либо программно в контроллере с помощью метода 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);
}
grid layout basic

Привязка данных

Привязка данных означает связывание визуального компонента с контейнером данных.

В компоненте 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 Указание контейнера, который содержит список элементов для отображения.

По умолчанию компонент отображает имя экземпляра сущности.

grid layout items
Вы можете переопределить отображение по умолчанию, настроив пользовательский рендерер.

Компонент также поддерживает отображение значений перечислений с помощью свойства itemsEnum.

<gridLayout itemsEnum="com.company.onboarding.entity.DayOfWeek"
            width="100%"/>

Рендеринг элементов

Существует возможность настройки рендеринга элементов. Рендерер применяется к каждому элементу для создания компонента, который его представляет.

Это можно выполнить двумя различными методами.

Программный подход

В контроллере экрана используйте либо:

  • Метод setRenderer();

  • Аннотацию @Supply.

Основываясь на предыдущем примере, мы можем создать renderer для отображения каждого пользователя в виде пользовательского компонента Card.

Показать код
@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 в виде карточки.
2 Создает базовый компонент Card с общим стилем.
3 Инициализирует содержимое карточки данными конкретного пользователя. Вызывается для каждого экземпляра карточки с соответствующей сущностью User.
4 Создает компонент image из изображения пользователя.
grid layout renderer

Декларативный подход

Альтернативно, вы можете отображать элементы, используя вложенный элемент fragmentRenderer.

  1. Создайте XML-дескриптор FragmentRenderer:

    <?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>
  2. Создайте Java-контроллер FragmentRenderer

    Класс фрагментного рендерера должен расширять базовый класс FragmentRenderer с параметрами типа, указывающими на корневой компонент и отображаемую сущность, например:

    Показать код
    @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;
        }
    }
  3. Используйте fragmentRenderer для компонента gridLayout:

    <gridLayout id="gridUsers"
                width="100%"
                itemsContainer="usersDc"
                gap="var(--lumo-space-m)">
        <fragmentRenderer class="com.company.onboarding.view.layout.gridlayout.CardFragment"/>
    </gridLayout>

Атрибуты

Общие атрибуты служат одной и той же цели для всех компонентов.

Следующие атрибуты специфичны для gridLayout:

Название

Описание

Значение по умолчанию

columnMinWidth

Задает минимальную ширину для столбцов сетки в gridLayout. Это гарантирует, что столбцы не станут слишком узкими при изменении размера контейнера. Значение представляется в виде CSS-значения длины (например, "50px", "10rem").

19rem

gap

Управляет промежутком между ячейками сетки (как между строками, так и между столбцами). Создает визуальное разделение между компонентами. Значение представляется в виде CSS-значения длины (например, "10px", "1rem").

var(--lumo-space-s)

Обработчики

Общие обработчики настраиваются одинаково для всех компонентов.

Следующие обработчики специфичны для gridLayout.

Чтобы сгенерировать заглушку обработчика в Jmix Studio, используйте вкладку Handlers панели инспектора Jmix UI, или команду Generate Handler, доступную на верхней панели контроллера экрана и через меню CodeGenerate (Alt+Insert / Cmd+N).

Название

Описание

itemLabelGenerator

Позволяет настроить надписи, отображаемые для каждого элемента. Смотрите Настройка отображения элементов.

renderer

Устанавливает рендерер элементов для gridLayout. Рендерер применяется к каждому элементу для создания компонента, который представляет данный вариант элемента. Смотрите Рендеринг элементов.