Reload view when @Published is changed

耗尽温柔 提交于 2021-02-05 11:48:06

问题


I want to be able to scan barcodes, then show the barcode at the bottom of the screen in a sheet, or a separate view.

When I update the 'barcode' variable which is @Published and accessed in other methods with @ObserveableObject, it doesn't update the view with the data from the barcode.

Content View

class ScannedCode: ObservableObject {
    @Published var barcode = ""
}

struct ContentView: View {
    @ObservedObject var barcode = ScannedCode()

    var body: some View {
        ZStack {
            ScannerView()
            FoundItemSheet()
        }
    }
}

Scanner View - scannedCode is linked to the @Published variable, so when this changes, I want it to reload FoundItemSheet() as a barcode has been found by the scanner

    class Coordinator: BarcodeScannerCodeDelegate, BarcodeScannerErrorDelegate {
    @ObservedObject var scannedCode = ScannedCode()
    
    private var scannerView: ScannerView

    init(_ scannerView: ScannerView) {
        self.scannerView = scannerView
    }
    
    func scanner(_ controller: BarcodeScannerViewController, didCaptureCode code: String, type: String) {
        self.scannedCode.barcode = code
        controller.resetWithError(message: "Error message")
    }

    func scanner(_ controller: BarcodeScannerViewController, didReceiveError error: Error) {
      print(error)
    }
}

FoundItemSheet() Loads BottomSheetView which is shown at the bottom of the screen in a box over the camera. I want this to update with the barcode data when it's found.

        struct FoundItemSheet: View {
        @State private var bottomSheetShown = false
        
        var body: some View {
            GeometryReader { geometry in
                BottomSheetView(
                    isOpen: self.$bottomSheetShown,
                    maxHeight: geometry.size.height * 0.7
                ) {
                    Color.blue
                }
            }.edgesIgnoringSafeArea(.all)
            }
        }

BottomSheetView - I have declared the @Published barcode variable in here, so when it changes, I want contentsInSlide to reload with the new barcode.

    struct BottomSheetView<Content: View>: View {
       @Binding var isOpen: Bool
       @State var showingDetail = false
       @ObservedObject var scannedCode = ScannedCode()

     ....
        private var contentInSlide: some View {
        VStack {
                Text("Value is: \(scannedCode.barcode)") //Doesn't show any value for the barcode
                    .foregroundColor(ColorManager.beautytruthGreen)
                    .font(.system(size: 22, weight: .medium))
                Button(action: {
                    self.showingDetail.toggle()
            }
        }

回答1:


The problem is that all of your views create their own ScannedCode instances. You need to create it only on the type that creates all other views and inject the same instance into each one of them.

From your code snippets it isn't really clear which view is the parent of which, so it's hard to give you a definitive answer with a code example, but in general, you should never create an @ObservableObject in a view itself, since that object will be recreated as soon as the view is reloaded. Instead, you should be creating your @ObservableObject on the view model or the parent view and injecting it into the child view that needs reloading.

Using below code, whenever scannedCode on the ParentView is updated, it reloads its ChildView with the updated ScannedCode.

struct ParentView: View {
    @Published var scannedCode = ScannedCode()

    var body: some View {
        ChildView(scannedCode: scannedCode)
    }
}

struct ChildView: View {
    @ObservedObject var scannedCode: ScannedCode

    var body: some View {
        Text(scannedCode.barCode)
    }
}


来源:https://stackoverflow.com/questions/62573769/reload-view-when-published-is-changed

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!