简体   繁体   English

SwiftUI - onChange 没有被调用

[英]SwiftUI - onChange not getting called

Adding the code first to help better understand the problem.首先添加代码以帮助更好地理解问题。

struct MainSetupView: View {
    @StateObject var viewModel: MainViewModel
    
    var body: some View {
        VStack {
            switch viewModel.state {
            case .idle:
                Color.clear.onAppear(perform: { viewModel.prepare() })
            case .loading:
                ProgressView()
            case .showMessage(let messageType, let messageText):
                ErrorHandlingView(messageType: messageType, messageText: messageText)
            }
        }.onAppear() {
            viewModel.state = .idle
        }
    }
}

struct ErrorHandlingView: View {
    @State var messageType: String
    var messageText: String

    @State private var messageViewImageDetails: (imageName: String, isSystemImage: Bool) = (imageName: "", isSystemImage: false)

    var body: some View {
        VStack {
            MessageViewWithActions(imageName: messageViewImageDetails.imageName, isSystemImage: messageViewImageDetails.isSystemImage, mainMessageText: messageText)
        }.onChange(of: messageType) {_ in
            self.messageViewImageDetails = getImageForError()
            // call more functions
        }
    }
    
    private func getImageForError() -> (imageName: String, isSystemImage: Bool) {
        var imageName = ""
        var isSystemImage = false
        
        switch messageType {
        case "noInternetError":
            imageName = "xmark.icloud"
            isSystemImage = true
        case "userSignedOut":
            imageName = "person.crop.circle.fill.badge.xmark"
            isSystemImage = true
        case "userSignedIn":
            imageName = "person.crop.circle.badge.checkmark"
            isSystemImage = true
        // more cases.
        default:
            imageName = "info.circle"
            isSystemImage = true
        }
        
        return (imageName: imageName, isSystemImage: isSystemImage)
    }
}

If "MainSetupView" is open and I receive a message ie .showMessage, "ErrorHandlingView" is displayed and I set "messageType" and "messageText" while calling ErrorHandlingView.如果“MainSetupView”打开并且我收到一条消息,即.showMessage,则会显示“ErrorHandlingView”,并且在调用ErrorHandlingView 时设置“messageType”和“messageText”。 While first message is being displayed, let's say I receive another message and "ErrorHandlingView" gets called again, now with a different message type.在显示第一条消息时,假设我收到另一条消息并且“ErrorHandlingView”再次被调用,现在使用不同的消息类型。 However "onChange(of: messageType)" in "ErrorHandlingView" never gets called.然而,“ErrorHandlingView”中的“onChange(of: messageType)”永远不会被调用。

"onChange(of: messageType)" calls a function "getImageForError" which tells the app which image to display based on the value of messageType. “onChange(of: messageType)”调用 function “getImageForError”,它告诉应用程序根据 messageType 的值显示哪个图像。 Since code in onChange is not getting executed, "getImageForError" never gets called and hence "messageViewImageDetails" is never populated which results in view without image.由于 onChange 中的代码没有被执行,因此永远不会调用“getImageForError”,因此永远不会填充“messageViewImageDetails”,这会导致视图没有图像。

Any idea why is.onChange() not being executed?知道为什么 is.onChange() 没有被执行吗? What am I doing wrong?我究竟做错了什么?

Note: I have lots of code and I am sharing pieces of code which I thought would be helpful.注意:我有很多代码,我正在分享一些我认为会有所帮助的代码。 Let me know if more code is needed.让我知道是否需要更多代码。

Edit : Adding code for MessageViewWithActions.编辑:为 MessageViewWithActions 添加代码。

struct MessageViewWithActions: View {
    // Image properties
    var imageName: String?
    var isSystemImage: Bool = false
    
    // Text properties
    var mainMessageText: String?

    var body: some View {
        ScrollView {
            VStack {
                Text("")
                VStack {
                    if let imageName = imageName {
                        if isSystemImage {
                            Image(systemName: imageName)
                        } else {
                            Image(imageName)
                        }
                    }
                }.frame(maxWidth: .infinity).padding(.bottom, 8)
                
                if let mainMessageText = mainMessageText {
                    Text(mainMessageText).font(.subheadline).fixedSize(horizontal: false, vertical: true)
                }
            }
        }
    }
}

Changing messageType to Binding var instead of State var worked.将 messageType 更改为 Binding var 而不是 State var 有效。 Sharing updated code for future:共享未来的更新代码:

struct MainSetupView: View {
    @StateObject var viewModel: MainViewModel
    @State var messageType: String
    
    var body: some View {
        VStack {
            switch viewModel.state {
            case .idle:
                Color.clear.onAppear(perform: { viewModel.prepare() })
            case .loading:
                ProgressView()
            case .showMessage(_, let messageText):
                ErrorHandlingView(messageType: messageType, messageText: messageText)
            }
        }.onAppear() {
            viewModel.state = .idle
        }.onReceive(viewModel.$state, perform: { (value) in
            switch value {
            case .showMessage(let messageType, _):
                self.messageType = messageType
            case .idle, .loading:
                print("")
            }
        })
    }
}

struct ErrorHandlingView: View {
    @Binding var messageType: String
    var messageText: String

    @State private var messageViewImageDetails: (imageName: String, isSystemImage: Bool) = (imageName: "", isSystemImage: false)

    var body: some View {
        VStack {
            MessageViewWithActions(imageName: messageViewImageDetails.imageName, isSystemImage: messageViewImageDetails.isSystemImage, mainMessageText: messageText)
        }.onChange(of: messageType) {_ in
            self.messageViewImageDetails = getImageForError()
            // call more functions
        }
    }
    
    private func getImageForError() -> (imageName: String, isSystemImage: Bool) {
        var imageName = ""
        var isSystemImage = false
        
        switch messageType {
        case "noInternetError":
            imageName = "xmark.icloud"
            isSystemImage = true
        case "userSignedOut":
            imageName = "person.crop.circle.fill.badge.xmark"
            isSystemImage = true
        case "userSignedIn":
            imageName = "person.crop.circle.badge.checkmark"
            isSystemImage = true
        // more cases.
        default:
            imageName = "info.circle"
            isSystemImage = true
        }
        
        return (imageName: imageName, isSystemImage: isSystemImage)
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM