1

我正在尝试使用拨动开关触发动作。在这种情况下,单击切换按钮后,控制台上不会显示打印消息“值确实发生了变化”。

这是针对 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 ")
         }
    }
}
4

2 回答 2

2

我将无耻地窃取@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 开始,有两个 Binding 扩展可供使用。第一个.onUpdate()在绑定值更改时触发,但不允许您访问旧值或新值。这只是为了副作用。我在上面使用这个只是因为print()不需要任何其他值。

如果您需要在闭包中使用 newValue,请使用.updated. 它的工作方式与它非常相似,.onChange(of:)只是它修改了 Binding 并且不允许您访问旧值。

于 2021-10-26T12:57:01.400 回答
1

不应该(至少从来没有以这种方式工作),因为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 !!
     }
}
于 2021-10-26T07:19:18.013 回答