Использование @ViewBuilder для создания представлений, которые поддерживают несколько детей - PullRequest
2 голосов
/ 10 июня 2019

Некоторые представления в SwiftUI, такие как VStack и HStack, поддерживают несколько представлений в качестве дочерних, например:

VStack {
  Text("hello")
  Text("world")
}

Насколько я понимаю, они используют ViewBuilder , чтобы сделать это возможным, как объяснено здесь .

Как мы можем использовать @ViewBuilder для создания наших собственных видов, которые поддерживают несколько дочерних элементов? Например, предположим, что я хочу создать Layout представление, которое принимает произвольные дочерние элементы - что-то вроде этого:

struct Layout : View {
  let content: Some View 

  var body : some View {
    VStack {
      Text("This is a layout")
      content()
    }
  } 
}

Есть идеи, как реализовать этот шаблон в SwiftUI?

Ответы [ 2 ]

3 голосов
/ 10 июня 2019

Вот примерное представление, которое ничего не делает, просто чтобы продемонстрировать, как использовать @ViewBuilder.

struct Passthrough<Content>: View where Content: View {

    let content: () -> Content

    init(@ViewBuilder content: @escaping () -> Content) {
        self.content = content
    }

    var body: some View {
        content()
    }

}

Использование:

Passthrough {
    Text("one")
    Text("two")
    Text("three")
}
1 голос
/ 10 июня 2019

Используя объявление VStack, нам нужно использовать @ViewBuilder для нашего параметра содержимого.Это замыкание, но оно не должно быть @escaping, не будет хорошо хранить замыкание, если нам нужны только данные из него.Я предполагаю, что из деклараций Apple.

Также я считаю, что @inlinable важно, потому что:

Атрибут @inlinable экспортирует тело функции как часть интерфейса модуля., делая его доступным для оптимизатора при обращении из других модулей. Подробнее здесь

struct Layout <Content> : View where Content : View {

        var content: Content

        @inlinable public init(@ViewBuilder content: () -> Content) {
            self.content = content()
        }

        var body : some View {
            VStack {
                Text("This is a layout")
                self.content
            }
        } 
    }

Для использования:

Layout {           
            Text("1")
            VStack {
                Text("1")
                Text("2")
            }
        }

UPD: As Matteo Pacini отмечена как вводящая в заблуждение информация о @escaping.

Нам нужно использовать @escaping для DynamicViewContent просмотров.@escaping используется структурами Apple для просмотра структур, принимающих коллекции (массив, диапазон и т. Д.).Потому что ForEach реализует DynamicViewContent - тип представления, который генерирует представления из базовой коллекции данных.List в его инициализаторах также ForEach в содержимом

 public init<Data, RowContent>(_ data: Data, selection: Binding<Selection>?, action: @escaping (Data.Element.IdentifiedValue) -> Void, rowContent: @escaping (Data.Element.IdentifiedValue) -> RowContent) where Content == ForEach<Data, Button<HStack<RowContent>>>, Data : RandomAccessCollection, RowContent : View, Data.Element : Identifiable
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...