#swiftui
#свифтуи
Вопрос:
Я создал пакет Swift, который создает несколько просмотров таблиц страниц из массива передаваемого ему содержимого:
import SwiftUI
public struct WhatsNewView<Content: View>: View {
let content: [Content]
public init(content: [Content]){
self.content = content
}
public var body: some View {
TabView {
ForEach(0..<content.count, id: .self) { pageNum in
WhatsNewPage(content: content[pageNum], pageNum: pageNum 1, totalPages: content.count)
}
}
.background(Color.white)
.ignoresSafeArea()
.tabViewStyle(PageTabViewStyle())
.indexViewStyle(PageIndexViewStyle(backgroundDisplayMode: .always))
}
}
Когда я вызываю его, я хочу передать любое простое или сложное представление для заполнения каждой страницы. Прямо сейчас я могу передать массив простых текстовых представлений следующим образом:
import SwiftUI
import WhatsNew
@main
struct mFood_Vendor: App {
@State var showWhatsNew = false
let whatsNew = WhatsNew()
var page1 = Text("Hello World")
var page2 = Text("Goodbye World")
var body: some Scene {
WindowGroup {
ContentView()
.fullScreenCover(isPresented: $showWhatsNew, content: {
let content = [page1, page2]
WhatsNewView(content: content)
})
.onAppear(perform: {
whatsNew.checkForUpdate(showWhatsNew: $showWhatsNew)
})
}
}
}
Я хочу, чтобы page1 и page2 были любым контентом, который человек хочет видеть на страницах «Что нового». Но если я изменю эти переменные на что-то другое, например, текст и изображение, я получаю сообщение об ошибке «Не удалось выполнить диагностику выражения».
В идеале я хотел бы иметь возможность передавать что-то вроде:
struct page1: View {
var body: some View {
VStack {
Text("something")
Image("plus")
}
}
}
Любая помощь будет признательна. Спасибо!
Ответ №1:
Вы можете использовать AnyView
, чтобы получить то, что вы хотите. В этом случае ваш код станет:
public struct WhatsNewView: View {
let content: [AnyView]
public init(content: [AnyView]){
self.content = content
}
public var body: some View {
TabView {
ForEach(0..<content.count, id: .self) { pageNum in
WhatsNewPage(content: content[pageNum], pageNum: pageNum 1, totalPages: content.count)
}
}
.background(Color.white)
.ignoresSafeArea()
.tabViewStyle(PageTabViewStyle())
.indexViewStyle(PageIndexViewStyle(backgroundDisplayMode: .always))
}
}
И, в качестве примера использования:
struct ContentView: View {
var body: some View {
let view1 = AnyView(Text("Hello World"))
let view2 = AnyView(Image(systemName: "star.fill"))
return WhatsNewView(content: [view1, view2])
}
}
РЕДАКТИРОВАТЬ: я только что узнал, что TabView
это может быть построено из TupleView
. Это означает, что, в зависимости от ваших потребностей, вы можете написать что-то вроде этого (что было бы здорово, потому что это не заставляет пользователей вашего пакета Swift переносить все представления внутрь AnyView
):
import SwiftUI
public struct WhatsNewView<Content: View>: View {
private let content: Content
public init(@ViewBuilder contentProvider: () -> Content){
content = contentProvider()
}
public var body: some View {
TabView {
content
}
.background(Color.white)
.ignoresSafeArea()
.tabViewStyle(PageTabViewStyle())
.indexViewStyle(PageIndexViewStyle(backgroundDisplayMode: .always))
}
}
Вы можете использовать его следующим образом:
struct ContentView: View {
var body: some View {
WhatsNewView {
Text("Hello World")
Image(systemName: "star.fill")
Color.red
VStack {
Text("Text1")
Text("Text2")
Text("Text3")
}
Button("Tap Me") {
print("Tapped")
}
Group {
Text("Group1")
Text("Group2")
}
}
}
}
Результатом является:
Ответ №2:
Оказывается, что если я оставлю WhatsNewView в покое, я могу просто сделать следующее:
struct mFood_Vendor: App {
@State var showWhatsNew = false
let whatsNew = WhatsNew()
var page1: some View {
VStack (alignment: .leading){
Text("Here is a list of new features:")
Text("Hello World")
Image(systemName: "plus")
}
}
var page2: some View {
Text("Goodbye World")
}
var body: some Scene {
WindowGroup {
ContentView()
.fullScreenCover(isPresented: $showWhatsNew, content: {
let content = [AnyView(page1), AnyView(page2)]
WhatsNewView (content: content)
})
.onAppear(perform: {
whatsNew.checkForUpdate(showWhatsNew: $showWhatsNew)
})
}
}
}
По сути, просто оберните каждую страницу содержимого в AnyView.
Комментарии:
1. Взгляните на мое РЕДАКТИРОВАНИЕ, я думаю, оно может быть вам полезно.
2. Мило! Мне действительно нравится это решение! Спасибо.