swiftui - 为什么 SwiftUI "Toggle.onChange"没有触发?

标签 swiftui toggle onchange

我在列表中有一个切换 UI 元素,我需要在切换状态更改时执行代码。据我了解,这是通过在切换上使用绑定(bind),然后在绑定(bind)变量上添加“.onChange:of:”来完成的。

完成:

//

import Foundation
import SwiftUI

struct User : Hashable, Identifiable {
    
    var isToggled = false
    
    var id: String
    var firstName: String?
    var lastName: String?
    var loggedIn: Bool = false
    var loggedInSince: String?
    var isActive: Bool?
    var isAdmin: Bool?
    
}

struct ListRow: View {
 @EnvironmentObject var userListModel: UserListModel

 @Binding var user: User

 var body: some View {
     Toggle(isOn: $user.loggedIn) {
         VStack {
           Text("\(user.firstName!) \(user.lastName!)")
             if user.loggedIn {
                 Text("Logged in since \(user.loggedInSince!)")
                     .font(Font.system(size: 10))
             }
             else {
                 Text("Logged out since \(user.loggedInSince!)")
                     .font(Font.system(size: 10))
             }
         }
     }
     .disabled(self.cantLogInOut())
     .onChange(of: user.loggedIn) { value in  // THIS ISN'T WORKING, IT'S NOT GETTING CALLED
         // action...
         print(value)
         userListModel.changeLogStatus(user: user)
     }
 }

因此,onChange ("print", "userListModel.changeLogStatus") 中的代码永远不会被调用。

我在控制台中得到了这个:

2022-02-12 22:56:39.860044-0500 TimeCard[10104:4072116] invalid mode 'kCFRunLoopCommonModes' provided to CFRunLoopRunSpecific - break on _CFRunLoopError_RunCalledWithInvalidMode to debug. This message will only appear once per execution.

我不知道这意味着什么,谷歌搜索它没有帮助,当我在该错误上放置符号断点时,调试器中没有显示任何有用的内容(它显示了一个堆栈跟踪,其中包含两个汇编代码段)主要。)

最佳答案

下面是一些代码,您可以使用它们“...在切换状态更改时执行代码”。 由于您使用 userListModel.changeLogStatus(user: user) 来记录 loggedIn 中的更改, 无需使用 @Binding var user: User,而是使用 @State var user: User

class UserListModel: ObservableObject {
    @Published var users = [User(isToggled: false, id: "1", firstName: "firstName-1", lastName: "lastName-1", loggedIn: false, loggedInSince: "yesterday", isActive: false, isAdmin: false),
                            User(isToggled: false, id: "2", firstName: "firstName-2", lastName: "lastName-2", loggedIn: false, loggedInSince: "yesterday", isActive: false, isAdmin: false),
                            User(isToggled: false, id: "3", firstName: "firstName-3", lastName: "lastName-3", loggedIn: false, loggedInSince: "yesterday", isActive: false, isAdmin: false)
    ]
    
    func changeLogStatus(user: User) {
        if let ndx = users.firstIndex(of: user) {
            users[ndx].loggedIn = user.loggedIn
        }
    }
}

struct User: Hashable, Identifiable {
    var isToggled = false
    var id: String
    var firstName: String?
    var lastName: String?
    var loggedIn: Bool = false
    var loggedInSince: String?
    var isActive: Bool?
    var isAdmin: Bool?
}

struct ListRow: View {
    @EnvironmentObject var userListModel: UserListModel
    
    @State var user: User  // <-- use @State
    
    var body: some View {
        Toggle(isOn: $user.loggedIn) {
            VStack {
                Text("\(user.firstName!) \(user.lastName!)")
                if user.loggedIn {
                    Text("Logged in since \(user.loggedInSince!)").font(Font.system(size: 10))
                }
                else {
                    Text("Logged in since \(user.loggedInSince!)").font(Font.system(size: 10))
                }
            }
        }
    //    .disabled(self.cantLogInOut())
        .onChange(of: user.loggedIn) { value in  // <-- THIS IS WORKING
            print("in onChange value: \(value)")
            userListModel.changeLogStatus(user: user)
        }
    }
}
    
    struct ContentView: View {
        @StateObject var model = UserListModel()
        
        var body: some View {
            List(model.users) { user in
                ListRow(user: user)
            }.environmentObject(model)
        }
    }
   

您也可以执行相反的操作,仅使用绑定(bind),而不使用EnvironmentObject UserListModel,如以下代码示例所示:

struct ListRow: View {
    @Binding var user: User  // <-- use @Binding, no need for userListModel here
    
    var body: some View {
        Toggle(isOn: $user.loggedIn) {
            VStack {
                Text("\(user.firstName!) \(user.lastName!)")
                if user.loggedIn {
                    Text("Logged in since \(user.loggedInSince!)").font(Font.system(size: 10))
                }
                else {
                    Text("Logged in since \(user.loggedInSince!)").font(Font.system(size: 10))
                }
            }
        }
        //.disabled(self.cantLogInOut())
        .onChange(of: user.loggedIn) { value in  // <-- THIS IS WORKING
            print("in onChange value: \(value)")
        }
    }
}

struct ContentView: View {
    @StateObject var model = UserListModel()
    
    var body: some View {
        List($model.users) { $user in   // <-- note the $ 
            ListRow(user: $user)
        }
    }
}
 

关于swiftui - 为什么 SwiftUI "Toggle.onChange"没有触发?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71097841/

相关文章:

ios - 当 View 位于 SwiftUI 中的 TabView 中时,NavigationView 标题不会出现

jquery - 使用 AJAX 提交多个表单的 OnChange 表单

javascript 更改需要刷新

用于检查时间格式的 JavaScript 正则表达式

ios - 动态 View 渲染,SwiftUI

swiftui - 如何收到符合协议(protocol)的 ObservedObject 更改的通知

swiftui - 如果 onPreferenceChange 在 SwiftUI 中的 ScrollView 内,为什么不调用它?

jquery - 试图删除菜单中的 div

android - 在 Android 上的根设备上切换 gps

javascript - 使用jQuery将声音从静音更改为取消静音