Bradley Ryan
Bradley Ryan

Reputation: 3

Advanced custom components in SwiftUI

I want to find the best way to structure a custom component with multiple slots for content.

This is the best tutorial I've found: https://www.hackingwithswift.com/plus/custom-swiftui-components/creating-a-flipview-to-provide-a-card-flip-effect

The code works, but I don't understand the syntax. Why does the first slot "left header actions" not need to be written?

import SwiftUI

struct ContentView: View {
    var body: some View {
        VStack {
            OnboardingHeader(
                title: "Title",
                paragraph: "Paragraph"
            ) {
                // why doesn't this require me to say "leftHeaderActions?"
                Text("Hi")
            } rightHeaderActions: {
                Text("Right")
            }
        }
    }
}

struct OnboardingHeader<LeftHeaderActions: View, RightHeaderActions: View>: View {

    var leftHeaderActions: () -> LeftHeaderActions
    var rightHeaderActions: () -> RightHeaderActions
    var title: String = ""
    var paragraph: String = ""

    init(title: String = "", paragraph: String = "", @ViewBuilder leftHeaderActions: @escaping () -> LeftHeaderActions, @ViewBuilder rightHeaderActions: @escaping () -> RightHeaderActions) {
        self.title = title
        self.paragraph = paragraph
        self.leftHeaderActions = leftHeaderActions
        self.rightHeaderActions = rightHeaderActions
    }


    var body: some View {

        VStack {
            HStack {
                leftHeaderActions()
                Spacer()
                rightHeaderActions()
            }
            .padding(.bottom, 16)

            Text(title)
                .frame(maxWidth: .infinity, alignment: .leading)
                .padding(.bottom, 4)//
            Text(paragraph)
                .frame(maxWidth: .infinity, alignment: .leading)
                .lineSpacing(1.8)
        }
        .padding(.top, 16)
        .padding(.bottom, 24)
    }
}

Upvotes: 0

Views: 960

Answers (1)

cluelessCoder
cluelessCoder

Reputation: 1088

It is a syntactic sugar of Swift compiler that you can omit name of first closure. What you shown is equivalent of:

OnboardingHeader(title: "Do you own a WalletOne hardware wallet?", paragraph: "Paragraph", leftHeaderActions: { 
                Text("Hi")
            }, rightHeaderActions: {
                Text("Right")
            })

Here, you have to provide the name, because you didn’t close the OnboardingHeader parenthesis (with ))

Much simpler example is Button - you can write the action closure inside the parenthesis:

Button("Text", action: { print("hi") })

Or outside it (without explicit “action”):

Button("Text") {
                print("hi")
            }

Upvotes: 1

Related Questions