SwiftUI:操作不会通过切换触发
SwiftUI: Action not triggering with toggle
我正在尝试使用拨动开关触发操作。在这种情况下,打印消息“value did change”在单击切换按钮后不会显示在控制台上。
这是针对 macOS 10.15 应用程序的,.onChange 将不起作用。
struct ContentView: View {
@State private var isToggle : Bool = false {
didSet {
print("value did change")
}
}
var body: some View {
Toggle(isOn: self.$isToggle){
Text("Toggle Label ")
}
}
}
不应该(至少从来没有以这种方式工作过),因为 Toggle
改变的不是状态本身(通过直接赋值给 属性)而是通过绑定包装值...改为使用
@State private var isToggle : Bool = false
var body: some View {
Toggle(isOn: self.$isToggle){
Text("Toggle Label ")
}
.onChange(of: isToggle) { _ in
print("value did change") // << here !!
}
}
我要厚颜无耻地盗用@Asperi 回答的第一部分,但第二部分是我的...
@State private var isToggle : Bool = false
var body: some View {
Toggle(isOn: self.$isToggle.onUpdate({
print("value did change") // << here !!
})){
Text("Toggle Label ")
}
}
extension Binding {
/// Adds a modifier for this Binding that fires an action when a specific
/// value changes.
///
/// You can use `onUpdate` to trigger a side effect as the result of a
/// `Binding` value changing.
///
/// `onUpdate` is called on the main thread. Avoid performing long-running
/// tasks on the main thread. If you need to perform a long-running task in
/// response to `value` changing, you should dispatch to a background queue.
///
/// The new value is NOT passed into the closure.
///
/// struct PlayerView: View {
/// var episode: Episode
/// @State private var playState: PlayState = .paused
///
/// var body: some View {
/// VStack {
/// Text(episode.title)
/// Text(episode.showTitle)
/// PlayButton(playState: $playState.updated {
/// model.playStateDidChange.update()
/// })
/// }
/// }
/// }
///
/// - Parameters:
/// - action: A closure to run when the value changes.
///
/// - Returns: A new binding value.
func onUpdate(_ action: @escaping () -> Void) -> Binding<Value> {
Binding(get: {
wrappedValue
}, set: { newValue in
wrappedValue = newValue
action()
})
}
}
extension Binding {
/// Adds a modifier for this Binding that fires an action when a specific
/// value changes.
///
/// You can use `updated` to trigger a side effect as the result of a
/// `Binding` value changing.
///
/// `updated` is called on the main thread. Avoid performing long-running
/// tasks on the main thread. If you need to perform a long-running task in
/// response to `value` changing, you should dispatch to a background queue.
///
/// The new value is passed into the closure.
///
/// struct PlayerView: View {
/// var episode: Episode
/// @State private var playState: PlayState = .paused
///
/// var body: some View {
/// VStack {
/// Text(episode.title)
/// Text(episode.showTitle)
/// PlayButton(playState: $playState.updated { newState in
/// model.playStateDidChange(newState)
/// })
/// }
/// }
/// }
///
/// - Parameters:
/// - action: A closure to run when the value changes.
///
/// - Returns: A new binding value.
func updated(_ action: @escaping (_ value: Value) -> Void) -> Binding<Value> {
Binding(get: {
wrappedValue
}, set: { newValue in
wrappedValue = newValue
action(newValue)
})
}
}
从 iOS 13、watchOS 6 和 macOS 10 开始,有两个绑定扩展可供使用。第一个 .onUpdate()
在绑定值更改时触发,但不会让您访问旧的或新的价值观。它只是为了副作用。我在上面使用这个只是因为 print()
不需要任何其他值。
如果您需要在闭包中使用 newValue,请使用 .updated
。它的工作方式与 .onChange(of:)
非常相似,只是它修改了绑定并且不会让您访问旧值。
我正在尝试使用拨动开关触发操作。在这种情况下,打印消息“value did change”在单击切换按钮后不会显示在控制台上。
这是针对 macOS 10.15 应用程序的,.onChange 将不起作用。
struct ContentView: View {
@State private var isToggle : Bool = false {
didSet {
print("value did change")
}
}
var body: some View {
Toggle(isOn: self.$isToggle){
Text("Toggle Label ")
}
}
}
不应该(至少从来没有以这种方式工作过),因为 Toggle
改变的不是状态本身(通过直接赋值给 属性)而是通过绑定包装值...改为使用
@State private var isToggle : Bool = false
var body: some View {
Toggle(isOn: self.$isToggle){
Text("Toggle Label ")
}
.onChange(of: isToggle) { _ in
print("value did change") // << here !!
}
}
我要厚颜无耻地盗用@Asperi 回答的第一部分,但第二部分是我的...
@State private var isToggle : Bool = false
var body: some View {
Toggle(isOn: self.$isToggle.onUpdate({
print("value did change") // << here !!
})){
Text("Toggle Label ")
}
}
extension Binding {
/// Adds a modifier for this Binding that fires an action when a specific
/// value changes.
///
/// You can use `onUpdate` to trigger a side effect as the result of a
/// `Binding` value changing.
///
/// `onUpdate` is called on the main thread. Avoid performing long-running
/// tasks on the main thread. If you need to perform a long-running task in
/// response to `value` changing, you should dispatch to a background queue.
///
/// The new value is NOT passed into the closure.
///
/// struct PlayerView: View {
/// var episode: Episode
/// @State private var playState: PlayState = .paused
///
/// var body: some View {
/// VStack {
/// Text(episode.title)
/// Text(episode.showTitle)
/// PlayButton(playState: $playState.updated {
/// model.playStateDidChange.update()
/// })
/// }
/// }
/// }
///
/// - Parameters:
/// - action: A closure to run when the value changes.
///
/// - Returns: A new binding value.
func onUpdate(_ action: @escaping () -> Void) -> Binding<Value> {
Binding(get: {
wrappedValue
}, set: { newValue in
wrappedValue = newValue
action()
})
}
}
extension Binding {
/// Adds a modifier for this Binding that fires an action when a specific
/// value changes.
///
/// You can use `updated` to trigger a side effect as the result of a
/// `Binding` value changing.
///
/// `updated` is called on the main thread. Avoid performing long-running
/// tasks on the main thread. If you need to perform a long-running task in
/// response to `value` changing, you should dispatch to a background queue.
///
/// The new value is passed into the closure.
///
/// struct PlayerView: View {
/// var episode: Episode
/// @State private var playState: PlayState = .paused
///
/// var body: some View {
/// VStack {
/// Text(episode.title)
/// Text(episode.showTitle)
/// PlayButton(playState: $playState.updated { newState in
/// model.playStateDidChange(newState)
/// })
/// }
/// }
/// }
///
/// - Parameters:
/// - action: A closure to run when the value changes.
///
/// - Returns: A new binding value.
func updated(_ action: @escaping (_ value: Value) -> Void) -> Binding<Value> {
Binding(get: {
wrappedValue
}, set: { newValue in
wrappedValue = newValue
action(newValue)
})
}
}
从 iOS 13、watchOS 6 和 macOS 10 开始,有两个绑定扩展可供使用。第一个 .onUpdate()
在绑定值更改时触发,但不会让您访问旧的或新的价值观。它只是为了副作用。我在上面使用这个只是因为 print()
不需要任何其他值。
如果您需要在闭包中使用 newValue,请使用 .updated
。它的工作方式与 .onChange(of:)
非常相似,只是它修改了绑定并且不会让您访问旧值。