Как создать представление SwiftUI, которое принимает необязательный вторичный аргумент View? - PullRequest
0 голосов
/ 15 октября 2019

Я пытаюсь создать пользовательское представление SwiftUI, которое действует как представления по умолчанию, где я могу добавить дополнительное представление к представлению с помощью метода или дополнительного аргумента инициализатора.

SomeCustomView(title: "string argument") {
    // some view
}

SomeCustomView(title: "hello") {
    // some view
}.sideContent {
    // another view
}

// This style is acceptable too
SomeCustomView(title: "hello", sideContent: { /* another view */ }) {
    // some view
}

Как я могу изменить это представлениевести себя как в приведенном выше примере?

struct SomeCustomView<Content>: View where Content: View {
    let title: String
    let content: Content

    init(title: String, @ViewBuilder content: () -> Content) {
        self.title = title
        self.content = content()
    }

    var body: some View {
        VStack {
            Text(title)
            content
        }
    }
}

В идеале у меня было бы два разных "шаблона" тела, между которыми я мог бы переключаться в зависимости от того, был ли вызван метод sideContent или был задан параметр sideContent,Например,

var body: some View {
    VStack {
        Text(title)
        content
    }
}

// or

var otherBody: some View {
    HStack {
        VStack {
            Text(title)
            content
        }
        sideContent
    }
}

Ответы [ 2 ]

0 голосов
/ 16 октября 2019

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

struct SomeCustomView<Content>: View where Content: View {
    let title: String
    let content: Content

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

    func sideContent<SideContent>(@ViewBuilder side: @escaping () -> SideContent) -> some View {
        HStack {
            body // body is just a View, so we can compose with this View
            side() 
        }
    }

    var body: some View {
        VStack {
            Text(title)
            content
        }
    }
}

Работает с вызовом метода или без него.

SomeCustomView(title: "string argument") {
    // some view
}

SomeCustomView(title: "hello") {
    // some view
}.sideContent {
    // another view
}
0 голосов
/ 15 октября 2019

Я бы предложил использовать ViewModifyer вместо пользовательских видов. Они работают следующим образом:

struct SideContent<SideContent: View>: ViewModifier {

    var title: String
    var sideContent: (() -> SideContent)?

    init(title: String) {
         self.title = title
    }

    init(title: String, @ViewBuilder sideContent: @escaping () -> SideContent) {
         self.title = title
         self.sideContent = sideContent
    }

    func body(content: Content) -> some View {
        HStack {
          VStack {
             Text(title)
             content
           }
           sideContent?()
        }
    }
}

Это может использоваться как SomeView().modifier(SideContent(title: "asdasd") { Text("asdasd")}), однако, если вы опустите сторону, вам все равно нужно будет указать ее тип SomeView().modifier(SideContent<EmptyView>(title: "asdasd"))

ОБНОВЛЕНИЕ

Удаление заголовка упрощает, как вы упомянули.

struct SideContent<SideContent: View>: ViewModifier {

    var sideContent: (() -> SideContent)

    init(@ViewBuilder sideContent: @escaping () -> SideContent) {
        self.sideContent = sideContent
    }

    func body(content: Content) -> some View {
        HStack {
            content
            sideContent()
        }
    }
}

Также вы можете сделать модификатор для Title.

struct Titled: ViewModifier {

    var title: String

    func body(content: Content) -> some View {
        VStack {
            Text(title)
            content
        }
    }
}

SomeView()
   .modifier(Titled(title: "Title"))
   .modifier(SideContent { Text("Side") })
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...