问题
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