Рендереры

Эта страница описывает общие API рендереров, такие как ComponentRenderer, LitRenderer и FragmentRenderer, которые используются в UI-компонентах. Предопределенные XML-рендереры, поддерживаемые атрибуты и примеры для конкретных компонентов смотрите в соответствующей документации.

Рендереры особенно полезны для:

  • Улучшенного визуального представления: Они позволяют включать визуальные элементы помимо простого текста, такие как иконки, изображения, индикаторы выполнения и другие, чтобы сделать данные более понятными и привлекательными. Это может улучшить общий пользовательский опыт и ясность интерфейса.

    radio button group renderer
  • Условное отображение: Рендереры могут реализовывать логику, изменяющую визуальное представление в зависимости от значения данных или другой контекстной информации. Например, рендерер может отображать зеленую галочку для успешных записей и красный крестик для неудачных.

    renderer 2
  • Сложные макеты: В случаях, требующих более сложных визуальных макетов, чем предлагает стандартное отображение, пользовательские рендереры обеспечивают гибкость в организации и отображении данных нестандартными способами. Это может включать в себя комбинирование нескольких элементов UI в одной ячейке компонента или создание полностью пользовательских макетов.

    renderer 3
Если нужно только изменить способ отображения значения, например даты или числа, используйте форматтер.

Рендерер компонентов

ComponentRenderer отображает элементы с помощью UI-компонентов, а не обычного текста. Его можно задать программно с помощью setRenderer() или предоставить из контроллера через @Supply.

ComponentRenderer создает UI-компоненты для отображаемых элементов и может влиять на производительность при работе с большими наборами данных. Если вам нужно только отобразить HTML-подобный контент, используйте LitRenderer.

ComponentRenderer можно создавать разными способами, в зависимости от того, как вы хотите создавать и обновлять компоненты. Ниже показаны доступные варианты.

Один обработчик

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

@Supply(to = "selectWithRenderer", subject = "renderer") (1)
private ComponentRenderer<Button, Department> selectWithRendererRenderer() {
    return new ComponentRenderer<>(item -> { (2)
        Button button = uiComponents.create(Button.class); (3)
        button.setText(item.getName());
        button.setIcon(VaadinIcon.DESKTOP.create());
        return button; (4)
    });
}
1 @Supply привязывает рендерер к selectWithRenderer.
2 Функция получает текущий элемент.
3 Экземпляр компонента создается и настраивается в этом же обработчике.
4 Функция возвращает компонент для текущего элемента.

Раздельные создание и привязка

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

@Supply(to = "dataGridCheckbox.active", subject = "renderer") (1)
private Renderer<User> dataGridCheckboxActiveRenderer() {
    return new ComponentRenderer<>(
            () -> {
                JmixCheckbox checkbox = uiComponents.create(JmixCheckbox.class); (2)
                checkbox.setReadOnly(true); (3)
                return checkbox; (4)
            },
            (checkbox, item) -> checkbox.setValue(item.getActive()) (5)
    );
}
1 @Supply привязывает рендерер к колонке active компонента dataGridCheckbox.
2 Поставщик создает экземпляр компонента JmixCheckbox.
3 Чекбокс переводится в режим "только для чтения".
4 Поставщик возвращает экземпляр компонента.
5 Consumer получает компонент и текущий элемент, затем устанавливает значение флажка из item.getActive().

Явное обновление

Используйте этот вариант, когда обновление элемента требует большего контроля, чем в предыдущих примерах. При обновлении можно переиспользовать текущий экземпляр компонента или заменить его новым.

@Supply(to = "dataGridStatus.status", subject = "renderer")
private Renderer<User> createUpdatableStatusRenderer() {
    return new ComponentRenderer<>(
            item -> {
                Span span = uiComponents.create(Span.class); (1)
                updateSpanBadge(span, item); (2)
                return span; (3)
            },
            (component, item) -> {
                if (item.getOnboardingStatus() == null) { (4)
                    updateUnknownStatus(component); (5)
                    return component; (6)
                } else {
                    return createStatusBadge(item); (7)
                }
            }
    );
}
1 Коллбэк создания создает начальный экземпляр Span.
2 Начальный компонент заполняется значением текущего элемента и оформляется как badge.
3 Коллбэк создания возвращает компонент.
4 Коллбэк обновления проверяет, есть ли у текущего элемента значение статуса.
5 Если значение отсутствует, коллбэк обновляет текущий экземпляр компонента.
6 Текущий компонент возвращается без замены.
7 Если значение присутствует, коллбэк создает и возвращает новый компонент для этого элемента.

Дополнительные примеры ComponentRenderer доступны в документации компонентов, которые его поддерживают:

LitRenderer

LitRenderer выполняет рендеринг контента с использованием HTML и синтаксиса привязки данных Lit; он более легковесный, чем компонентные рендереры.

LitRenderer позволяет определять HTML-шаблон и связывать свойства сущности с переменными шаблона.

@Supply(to = "dataGridLit.userInfo", subject = "renderer")
private Renderer<User> dataGridLitUserInfoRenderer() {
    return LitRenderer.<User>of("${item.firstName}<br>${item.lastName}<br>${item.email}")
            .withProperty("firstName", User::getFirstName)
            .withProperty("lastName", User::getLastName)
            .withProperty("email", User::getEmail);
}
renderer 5
LitRenderer выполняет рендеринг эффективно и идеально подходит для высокопроизводительных приложений, требующих частых обновлений. Его легковесность делает его подходящим для приложений со множеством компонентов или динамическим контентом.

LitRenderer можно использовать в следующих компонентах пользовательского интерфейса:

Рендерер фрагментов

Рендереры для virtualList, dataGrid и других компонентов могут быть определены с помощью фрагментов. Специальный XML-элемент fragmentRenderer используется для декларативного описания рендерера.

Как и обычные фрагменты, fragmentRenderer определяется с помощью дескриптора и контроллера Java.

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

    Дескриптор может содержать необязательный instanceContainer для сущности, которая будет использоваться рендерером.

    <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>
            <hbox>
                <icon icon="ANGLE_DOUBLE_RIGHT"/>
                <formLayout id="form" dataContainer="userDc">
                    <textField property="username" readOnly="true"/>
                    <textField property="firstName" readOnly="true"/>
                    <textField property="lastName" readOnly="true"/>
                    <textField property="email" readOnly="true"/>
                </formLayout>
            </hbox>
        </content>
    </fragment>
    Если instanceContainer не определен, вы можете использовать метод FragmentRenderer.getItem() для обработки рендеринга.
  2. Создайте FragmentRenderer Java-контроллер

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

    @FragmentDescriptor("user-fragment.xml") (1)
    @RendererItemContainer("userDc") (2)
    public class UserFragment extends FragmentRenderer<HorizontalLayout, User> {
    }
    1 Аннотация @FragmentDescriptor задает строковое значение - путь к XML-файлу, используемому для инициализации фрагмента.
    2 Аннотация @RendererItemContainer используется для указания контейнера данных, принимающего отображаемую сущность.
  3. Используйте FragmentRenderer в экране

    Выберите компонент, в котором вы хотите отобразить элементы, и добавьте элемент fragmentRenderer. Этот элемент требует атрибут class, указывающий полное имя класса (FQN), расширяющего абстрактный класс io.jmix.flowui.fragmentrenderer.FragmentRenderer.

    <virtualList itemsContainer="usersDc">
        <fragmentRenderer
                class="com.company.onboarding.view.component.virtuallist.UserFragment"/>
    </virtualList>

    Чтобы добавить fragmentRenderer в Jmix Studio, выберите UI-компонент в XML-дескрипторе экрана или на панели структуры Jmix UI и нажмите кнопку Add→FragmentRenderer на панели инспектора Jmix UI.

    Элемент fragmentRenderer также поддерживает загрузку свойств, так же как и элемент fragment.

renderer 6

Вы можете использовать fragmentRenderer в следующих UI-компонентах: