Фрагменты
Фрагмент - это структурный элемент пользовательского интерфейса, который можно использовать в качестве компонента экранов или других фрагментов. Фрагмент является композитным компонентом и обладает следующими дополнительными возможностями:
-
Содержимое фрагмента можно определять в формате XML.
-
Элемент XML
fragment
позволяет декларативно включать фрагменты в экраны и другие фрагменты. -
Класс фрагмента (называемый также контроллер) поддерживает инжекцию бинов Spring и UI-компонентов фрагмента, а также аннотированные методы в качестве обработчиков.
-
Когда фрагмент полностью инициализирован, отправляется событие
ReadyEvent
. -
В XML фрагмента можно определить действия и компоненты данных (контейнеры и загрузчики). Компоненты данных можно пометить как
provided
для их получения из экрана-владельца. -
Студия предлагает шаблон Blank fragment для генерации фрагментов, отображает их в окне инструментов Jmix и позволяет использовать визуальный дизайнер так же, как для экранов.
Фрагменты в настоящее время не поддерживают фасеты.
Содержимое фрагмента
Аннотация @FragmentDescriptor
определяет строковое значение, которое представляет собой путь к файлу XML, используемому для инициализации фрагмента. Если значение содержит только имя файла (и не начинается с /
), то предполагается, что файл находится в пакете класса фрагмента.
Элементы, доступные в XML-дескрипторе:
-
content
- обязательный элемент, содержащий макета фрагмент (аналогично элементуlayout
экрана). Поскольку корневым компонентом фрагмента может быть любой компонент, уcontent
нет атрибутов и он не представляет какой-либо UI-компонент. -
actions
- необязательный элемент действий фрагмента (аналогичный элементуactions
экрана). Если для действия задано сочетание клавиш, оно привязывается к корневому компоненту фрагмента. Другими словами, сочетание клавиш может быть активировано только в том случае, если фокус находится внутри фрагмента. -
data
— необязательный элемент данных фрагмента (аналогичный элементуdata
экрана). Фрагмент может определить свои собственные контейнеры данных и загрузчики, или получить их по идентификатору из включающего экрана или фрагмента, как описано в разделе Использование компонентов данных.
Пример XML-дескриптора фрагмента:
<fragment xmlns="http://jmix.io/schema/flowui/fragment">
<data>
<collection id="customersDc"
class="com.company.onboarding.entity.Customer">
<fetchPlan extends="_base">
<property name="city" fetchPlan="_base"/>
</fetchPlan>
<loader id="customersDl" readOnly="true">
<query>
<![CDATA[select e from Customer e]]>
</query>
</loader>
</collection>
</data>
<content>
<vbox id="root" padding="false">
<genericFilter id="genericFilter"
dataLoader="customersDl">
<properties include=".*"/>
</genericFilter>
<hbox id="buttonsPanel" classNames="buttons-panel">
<button id="createBtn" action="customersDataGrid.create"/>
<button id="editBtn" action="customersDataGrid.edit"/>
<button id="removeBtn" action="customersDataGrid.remove"/>
<simplePagination id="pagination" dataLoader="customersDl"/>
</hbox>
<dataGrid id="customersDataGrid"
width="100%"
minHeight="20em"
dataContainer="customersDc"
columnReorderingAllowed="true">
<actions>
<action id="create" type="list_create"/>
<action id="edit" type="list_edit"/>
<action id="remove" type="list_remove"/>
</actions>
<columns resizable="true">
<column property="city"/>
<column property="level"/>
<column property="age"/>
<column property="martialStatus"/>
<column property="hobby"/>
<column property="firstName"/>
<column property="lastName"/>
<column property="email"/>
<column property="rewardPoints"/>
</columns>
</dataGrid>
</vbox>
</content>
</fragment>
API фрагментов
-
getFragmentData()
- возвращает объектFragmentData
, определяющий методы взаимодействия с компонентами данных фрагмента. -
getFragmentActions()
- возвращает объектFragmentActions
, определяющий методы взаимодействия с действиями фрагмента. -
getParentController()
- возвращает родительский объектFragmentOwner
. Это может бытьView
илиFragment
. -
findInnerComponent()
/getInnerComponent()
- возвращают внутренний компонент с указанным идентификатором. Эти методы ищут только среди компонентов, добавленных через XML-дескриптор.
События фрагментов
-
ReadyEvent
- событие, которое посылается после создания фрагмента и всех его декларативно определенных внутренних компонентов, и полной их инициализации. В обработчике этого события можно выполнить окончательную настройку фрагмента и его внутренних компонентов. Например:CustomerListFragment.java@FragmentDescriptor("customer-list-fragment.xml") public class CustomerListFragment extends Fragment<VerticalLayout> { @Subscribe public void onReady(final ReadyEvent event) { getFragmentData().loadAll(); (1) } }
1 Вызывает метод load()
всех загрузчиков фрагмента, включая предоставленные.
Автоматическое связывание
Аналогично экранам, фрагменты поддерживают инжекцию компонентов, определенных в XML, и вызов аннотированных методов обработчика:
@ViewComponent
public JmixButton button; (1)
@ViewComponent
public CollectionContainer<Customer> collectionDc; (2)
@Subscribe
public void onReady(ReadyEvent event) { (3)
// ...
}
@Subscribe(value = "button", subject = "clickListener")
public void onButtonClick(ClickEvent<JmixButton> event) { (4)
// ...
}
@Install(to = "collectionDl", target = Target.DATA_LOADER)
public List<Customer> collectionDlLoadDelegate(LoadContext<Customer> loadContext) { (5)
return loadCustomers(loadContext);
}
@Supply(to = "dataGrid.name", subject = "renderer")
public Renderer<Customer> dataGridNameRenderer() { (6)
return createRenderer();
}
1 | Инжектирует UI-компонент. |
2 | Инжектирует контейнер данных. |
3 | Подписывается на событие ReadyEvent фрагмента. |
4 | Подписывается на событие ClickEvent кнопки. |
5 | Устанавливает делегат загрузки. |
6 | Предоставляет Renderer для таблицы данных. |
В дополнение к этому, можно подписаться на события включающего экрана, определив target = Target.HOST_CONTROLLER
в аннотации @Subscribe
:
@Subscribe(target = Target.HOST_CONTROLLER)
public void onHostInit(View.InitEvent event) {
// ...
}
@Subscribe(target = Target.HOST_CONTROLLER)
public void onHostBeforeShow(View.BeforeShowEvent event) {
// ...
}
@Subscribe(target = Target.HOST_CONTROLLER)
public void onHostReady(View.ReadyEvent event) {
// ...
}