如何从 swiftUI 中的单独视图正确更新状态变量

问题描述 投票:0回答:1

我有一个

WineInfoView
,它显示特定葡萄酒的一系列图像。水平滚动中的最后一个“图像”是一个空白图像,点击该图像时会显示用户的相机胶卷并允许他们添加新图像。

当我在

HorizontalImageScrollView()
中测试它时,我正确地将新图像放置在最后一个“图像”之前,但在“WineInfoView”中测试或在我的设备上运行应用程序时可以看到更改。

这是两个视图的代码:

WineInfoView

struct WineInfoView: View {
    //ADD MODEL HERE
    @State var wine: Wine
    
    var body: some View {
        HorizontalImageScrollView(wine: $wine)         
    }
}

水平图像滚动:

struct HorizontalImageScrollView: View {
    @Binding var wine: Wine
    
    //For selecting / adding phtotos
    @State var photoPickerPresented: Bool = false
    @State var cameraPresente: Bool = false
    @State private var selectedItem: PhotosPickerItem?
    @State var image: UIImage?
    
    var body: some View {
        ScrollView(.horizontal, content: {
            //parse through images that exist
            HStack {
                ForEach(wine.images, id: \.self) { image in
                    Image(uiImage: image)
                        .resizable()
                        .scaledToFill()
                        .frame(width: 175, height: 250)
                        .clipShape(RoundedRectangle(cornerRadius: 25.0))
                        .padding()
                }
                ////////////////////////////////////////////////////////////////////////////
                ///// PHOTO PICKER
                //empty "Image" to add more pictures
                PhotosPicker(selection: $selectedItem, label: {
                    ZStack {
                        Color(uiColor: UIColor(rgb: 0xEDEDE9))
                            .frame(width: 175, height: 250)
                            .clipShape(RoundedRectangle(cornerRadius: 25.0))
                            .padding([.leading,.trailing])
                        Image(systemName: "plus.circle.fill")
                    }
                })
                .onChange(of: selectedItem) {
                    Task {
                        if let data = try? await selectedItem?.loadTransferable(type: Data.self) {
                            image = UIImage(data: data)
                            //add image to local object
                            wine.images.append(image!)
                            //update record in DB
                            updateWineRecordPhotos(wine.images)
                        } else {
                            print("Failed to load the image")
                        }
                    }
                }
                ////////////////////////////////////////////////////////////////////////////
            }
            
        })
    }
}

有人可以解释为什么更改没有显示在

WineInfoView

中吗?
ios swift swiftui photosui
1个回答
0
投票

您应该在您的

WineInfoView
中实例化一个 wine 对象, 例如:
@State private var wine: Wine = Wine(.... ,images: [])
,这样就可以在
WineInfoView
中添加和显示图像。

同时避免使用强制展开

!
,例如:
wine.images.append(image!)
,请参阅代码更新。

这是我的测试代码,当我选择照片而不是视频等时,它对我来说效果很好......

在 MacOS 14.3 上,使用 Xcode 15.2,在真实的 ios 17 设备(不是预览版)和 macCatalyst 上进行测试。在旧系统上可能会有所不同。

// for testing
struct Wine: Identifiable {
    let id = UUID()
    var name: String
    var images: [UIImage]
    // ....
}

struct WineInfoView: View {
    @State private var wine: Wine = Wine(name: "Chateau Cardboard", images: []) // <--- here
    
    var body: some View {
        HorizontalImageScrollView(wine: $wine)
    }
}

struct HorizontalImageScrollView: View {
    @Binding var wine: Wine
    
    //For selecting / adding phtotos
    @State var photoPickerPresented: Bool = false
    @State var cameraPresente: Bool = false
    @State private var selectedItem: PhotosPickerItem?
    @State var image: UIImage?  // <--- not used
    
    var body: some View {
        ScrollView(.horizontal, content: {
            //parse through images that exist
            HStack {
                ForEach(wine.images, id: \.self) { image in
                    Image(uiImage: image)
                        .resizable()
                        .scaledToFill()
                        .frame(width: 175, height: 250)
                        .clipShape(RoundedRectangle(cornerRadius: 25.0))
                        .padding()
                }
                //empty "Image" to add more pictures
                PhotosPicker(selection: $selectedItem, label: {
                    ZStack {
                        Color(uiColor: .lightGray)
                            .frame(width: 175, height: 250)
                            .clipShape(RoundedRectangle(cornerRadius: 25.0))
                            .padding([.leading,.trailing])
                        Image(systemName: "plus.circle.fill")
                    }
                })
                .onChange(of: selectedItem) {
                    Task {
                        if let data = try? await selectedItem?.loadTransferable(type: Data.self),
                            let img = UIImage(data: data) {
                            image = img
                            //add image to local object
                            wine.images.append(img)
                            //update record in DB
                            // updateWineRecordPhotos(wine.images) // for testing
                        } else {
                            print("----> Failed to load the image")
                        }
                    }
                }
            }
        })
    }
}

编辑-1:

如果您将

wine
对象从父视图传递到
WineInfoView
, 然后使用
Binding
,例如:

struct ContentView: View {
    @State private var wine: Wine = Wine(name: "Chateau Cardboard", images: []) // <--- here
    
    var body: some View {
        WineInfoView(wine: $wine) // <--- here
    }
}

struct WineInfoView: View {
    @Binding var wine: Wine // <--- here
    
    var body: some View {
        HorizontalImageScrollView(wine: $wine)
    }
}

struct HorizontalImageScrollView: View {
    @Binding var wine: Wine  // <--- here
    // .....
© www.soinside.com 2019 - 2024. All rights reserved.