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

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

Я нашел эту ссылку, которая проделала мне большую часть пути, но, похоже, я просто не могу пройти последнюю милю.

Как передать одно представление SwiftUI как переменная для другой структуры представления

Вот созданная мной структура NavigationLink многократного использования:

struct MainMenuButtonView<Content: View>: View {
    
    var imageName: String
    var title: String
    var description: String
    var content: Content
    
    init(@ViewBuilder content: @escaping () -> Content) {
        self.content = content()
    }
    
    var body: some View {
        VStack {
            NavigationLink(destination: content) {
                Image(imageName)
                    .resizable()
                    .frame(width: 100, height: 100)
                Text(title)
                    .font(.title)
                Text(description)
                    .foregroundColor(Color(UIColor.systemGray2))
                    .multilineTextAlignment(.center)
                    .font(.footnote)
                    .frame(width: 175)
            }
            .buttonStyle(PlainButtonStyle())
        }
    }
}

В настоящее время у меня нет никаких ошибок по этой части, но это не значит, что с этим что-то не так.

И вот где я его использую, в настоящее время я только что показал один, но у меня будет больше, когда он заработает.

struct MainMenuView: View {
    
    var body: some View {
        NavigationView {
            MainMenuButtonView(imageName: "List Icon",
                               title: "Lists",
                               description: "Auto generated shopping lists by store",
                               content: TestMainView(testText: "Lists"))
            }
            .buttonStyle(PlainButtonStyle())
            .navigationBarTitle(Text("Main Menu"))
        }
    }
}

Когда я оставляю его, как указано выше, он сообщает мне, что есть дополнительный аргумент и что Contect не может быть выведен. Xcode предлагает исправление, и после исправления он выглядит так

MainMenuButtonView<Content: View>(imageName: "List Icon",

Но затем я получаю сообщение об ошибке, что он не может найти «Контент» в области видимости. Я знаю, что основное различие между моим вопросом и примером, который я привел выше, - это мое представление, которое я передаю, также имеет аргументы. Я не уверен, что я должен также помещать все аргументы в выноску в ‹›.

Спасибо за любую помощь, которую вы можете оказать.


person Jason Brady    schedule 18.01.2021    source источник


Ответы (1)


Вам необходимо исправить init в MainMenuButtonView:

struct MainMenuButtonView<Content: View>: View {
    var imageName: String
    var title: String
    var description: String
    var content: () -> Content // change to closure

    // add all parameters in the init
    init(imageName: String, title: String, description: String, @ViewBuilder content: @escaping () -> Content) {
        self.imageName = imageName // assign all the parameters, not only `content`
        self.title = title
        self.description = description
        self.content = content
    }

    var body: some View {
        VStack {
            NavigationLink(destination: content()) { // use `content()`
                Image(imageName)
                    .resizable()
                    .frame(width: 100, height: 100)
                Text(title)
                    .font(.title)
                Text(description)
                    .foregroundColor(Color(UIColor.systemGray2))
                    .multilineTextAlignment(.center)
                    .font(.footnote)
                    .frame(width: 175)
            }
            .buttonStyle(PlainButtonStyle())
        }
    }
}

Кроме того, вам необходимо передать закрытие параметру content (как вы указали в init):

struct MainMenuView: View {
    var body: some View {
        NavigationView {
            MainMenuButtonView(
                imageName: "List Icon",
                title: "Lists",
                description: "Auto generated shopping lists by store",
                content: { TestMainView(testText: "Lists") } // pass as a closure
            )
            .navigationBarTitle(Text("Main Menu"))
        }
    }
}
person pawello2222    schedule 18.01.2021
comment
Сработало как шарм, спасибо! Я только что понял, что у меня все еще есть NavigationLink в MainMenuView, так что всем, кто читает, он вам не нужен в обоих местах. - person Jason Brady; 19.01.2021
comment
@JasonBrady Верно, я не заметил - я убрал лишний NavigationLink из своего ответа. - person pawello2222; 19.01.2021
comment
Я сделал то же самое и со своим. - person Jason Brady; 19.01.2021