英文:
How do I pass a value from a Child view across multiple views in SwiftUI?
问题
在我项目中,当我点击按钮时,我需要将“Product”的id打印到控制台。我可以在一个子视图中访问产品的“id”并将其打印到控制台(在子视图内部被点击时)。我需要在不同视图中的按钮中使用这个id。我该如何做到这一点?这是视图的结构:
struct IntroView: View {
var body: some View {
VStack {
CustomSelectView()
Button("Continue") {
// 这里是需要访问ProductRowViewOnboard()中的“selectedProduct”数据的地方
}
}
}
}
struct CustomSelectView: View {
@State private var showingProductSheet = false
var body: some View {
HStack {
VStack {
Text("Select Product 1")
}
.onTapGesture {
print("Select Product 1 Tapped...")
showingProductSheet.toggle()
}
.sheet(isPresented: $showingProductSheet) {
ProductSheetOnboard()
}
VStack {
Text("Select Product 2")
}
.onTapGesture {
print("Select Product 2 Tapped...")
showingProductSheet.toggle()
}
.sheet(isPresented: $showingProductSheet) {
ProductSheetOnboard()
}
}
}
}
struct ProductSheetOnboard: View {
@Environment(\.dismiss) var dismiss
@StateObject var marketplaceModel = MarketplaceViewModel()
let product_id: String
var body: some View {
var columns = Array(repeating: GridItem(.flexible()), count: 2)
let defaults = UserDefaults.standard
let keyString = defaults.string(forKey: "key") ?? ""
ScrollView(.vertical, showsIndicators: false) {
VStack {
ForEach(marketplaceModel.filteredProduct, id:\.self){ product in
ProductRowViewOnboard(productData: product, product_id: product_id ?? "")
}
}
}
.onAppear {
let defaults = UserDefaults.standard
let keyString = defaults.string(forKey: "key") ?? ""
self.marketplaceModel.fetchProductTags(key: keyString ?? "")
self.marketplaceModel.fetchMarketProducts(key: keyString ?? "")
}
}
}
struct ProductRowViewOnboard: View {
@Environment(\.dismiss) var dismiss
@State var selectedProduct : ProductTile?
var productData: ProductRow
let product_id: String
var body: some View {
HStack {
ScrollView {
HStack {
ForEach(productData.products ?? []) { product in
ProductView(productData: product)
.onTapGesture {
selectedProduct = product
// 下面的print语句有效
print("Product id: \(selectedProduct?.id ?? "")")
let defaults = UserDefaults.standard
let keyString: String? = defaults.string(forKey: "key") ?? ""
// 这里需要访问selectedProduct中的数据以在IntroView()中使用
}
}
}
}
}
}
}
英文:
In my project, I need an id of a 'Product' to be printed to the console when I tap a button. I am accessing an 'id' of a product in one of my child views and printing it to the console (when it is tapped within a child view). I need to use this id in a button in a different view. How do I do this? Here is the structure of the views:
struct IntroView: View {
var body: some View {
VStack {
CustomSelectView()
Button("Continue") {
//Here is where the 'selectedProduct' data in ProductRowViewOnboard() needs to be accessed
}
}
}
}
struct CustomSelectView: View {
@State private var showingProductSheet = false
var body: some View {
HStack {
VStack {
Text("Select Product 1")
}
.onTapGesture {
print("Select Product 1 Tapped...")
showingProductSheet.toggle()
}
.sheet(isPresented: $showingProductSheet) {
ProductSheetOnboard()
}
VStack {
Text("Select Product 2")
}
.onTapGesture {
print("Select Product 2 Tapped...")
showingProductSheet.toggle()
}
.sheet(isPresented: $showingProductSheet) {
ProductSheetOnboard()
}
}
}
}
struct ProductSheetOnboard: View {
@Environment(\.dismiss) var dismiss
@StateObject var marketplaceModel = MarketplaceViewModel()
let product_id: String
var body: some View {
var columns = Array(repeating: GridItem(.flexible()), count: 2)
let defaults = UserDefaults.standard
let keyString = defaults.string(forKey: "key") ?? ""
ScrollView(.vertical, showsIndicators: false) {
VStack {
ForEach(marketplaceModel.filteredProduct, id:\.self){ product in
ProductRowViewOnboard(productData: product, product_id: product_id ?? "")
}
}
}
.onAppear {
let defaults = UserDefaults.standard
let keyString = defaults.string(forKey: "key") ?? ""
self.marketplaceModel.fetchProductTags(key: keyString ?? "")
self.marketplaceModel.fetchMarketProducts(key: keyString ?? "")
}
}
}
struct ProductRowViewOnboard: View {
@Environment(\.dismiss) var dismiss
@State var selectedProduct : ProductTile?
var productData: ProductRow
let product_id: String
var body: some View {
HStack {
ScrollView {
HStack {
ForEach(productData.products ?? []) { product in
ProductView(productData: product)
.onTapGesture {
selectedProduct = product
//The following print statement works
print("Product id: \(selectedProduct?.id ?? "")")
let defaults = UserDefaults.standard
let keyString: String? = defaults.string(forKey: "key") ?? ""
// The data in selectedProduct here needs to be accessed in IntroView()
}
}
}
}
}
}
}
In the last view I provided (ProductRowViewOnboard) in the .onTapGesture{}, I have accused the id of the product. I need to access this value in IntroView() so I can use it in the Button.
I can't seem to do it.
答案1
得分: 1
你需要先将状态提升到需要的位置,然后传递let
以进行读取访问,或者传递@Binding var
以进行读/写访问,例如:
struct IntroView: View {
@State var selectedProduct : ProductTile?
var body: some View {
...
ProductRowViewOnboard(selectedProduct: $selectedProduct)
...
}
}
struct ProductRowViewOnboard: View {
@Binding var selectedProduct : ProductTile?
}
此外,在SwiftUI中,View
结构体应该是您封装视图数据的主要方式。不要使用视图模型对象,因为您将在其中难以传递其他视图数据(正如您可能通过非标准使用onAppear
所经历的);您还将遇到SwiftUI通过值类型设计为View
结构体以消除的一致性错误。
英文:
You need to move the state up to where it is needed first and then pass down let
for read access or @Binding var
for read/write access, e.g.
struct IntroView: View {
@State var selectedProduct : ProductTile?
var body: some View {
...
ProductRowViewOnboard(selectedProduct: $selectedProduct)
...
}
}
struct ProductRowViewOnboard: View {
@Binding var selectedProduct : ProductTile?
}
Also in SwiftUI, the View
struct should be your primary encapsulation of view data. Don't use view model objects because you'll have trouble getting other view data in and out of them (as you have probably experienced by your non-standard use of onAppear
); you'll also get consistency bugs which SwiftUI's use of value types for the View
struct is designed to eliminate.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论