Советы и трюки при использовании SwiftUI ViewBuilder
Тип ViewBuilder — это ключевая часть архитектуры SwiftUI. Именно благодаря ему мы можем описывать несколько представлений (View) в пределах одной области (например, в body или внутри замыканий HStack, VStack и т.д.) без необходимости вручную объединять или оборачивать их.
Интересный факт: ViewBuilder можно долго использовать, даже не осознавая, что он вообще существует. Чаще всего мы не указываем его явно — всё уже аннотировано соответствующим атрибутом @ViewBuilder.
Протокол View, который используется для создания пользовательских представлений, сам по себе уже содержит @ViewBuilder в определении body:
Это позволяет нам использовать управляющие конструкции (if, else, switch) прямо в body, даже если ветви возвращают разные типы:
Когда использовать ViewBuilder напрямую
Хотя @ViewBuilder применяется автоматически, бывают ситуации, когда его прямое использование даёт большую гибкость. Рассмотрим примеры.
Пользовательские контейнеры
Мы можем аннотировать любое свойство, функцию или замыкание с помощью @ViewBuilder, чтобы добавить “DSL-подобные” возможности, как в стандартных элементах SwiftUI.
Допустим, мы хотим создать собственный Container, который содержит заголовок и контент:
Такой контейнер можно вызвать так:
Теперь добавим @ViewBuilder:
С этими аннотациями header и content теперь ожидаются как замыкания. Это позволяет использовать управляющие конструкции:
Делание компонентов необязательными
Если нам нужно сделать заголовок необязательным, мы можем создать расширение с EmptyView:
Или — ещё более удобно — задать EmptyView.init как значение по умолчанию:
Теперь можно вызывать:
Обработка нескольких выражений
Если в header мы добавим несколько элементов, например:
SwiftUI обработает это как Group, то есть они будут независимыми по стилю и размещению. Чтобы этого избежать, можно обернуть содержимое в VStack
И аналогично для content.
Структурирование больших вью через функции
Можно выносить части UI в отдельные приватные функции с @ViewBuilder:
Но тут возникает нюанс: header() на самом деле возвращает несколько View, а не один. Поэтому лучше убрать @ViewBuilder и явно обернуть в VStack:
А для content можно оставить @ViewBuilder, если он содержит if/else.
Заключение
ViewBuilder — мощный инструмент SwiftUI, который позволяет писать гибкие и выразительные пользовательские интерфейсы. Используя его в своих компонентах, мы можем создавать API, которые выглядят и ощущаются как нативные SwiftUI-виды. Это улучшает читаемость и поддержку кода.