swift - UIViewRepresentable 没有更新绑定(bind)到 ObservedObject 属性?

标签 swift swiftui uiviewrepresentable swiftui-14.2-defect

此 View 是一个适用于我的 SwiftUI 项目的 UIKit slider ,因为在 SwiftUI 中 Slider 无法更改其轨道颜色,这可能是一个错误,因为您应该能够使用 .accentColor 更改它。不管怎样,这个 slider 根据它的值改变它的轨道颜色,从绿色到红色。如果 value 绑定(bind)到普通的 @State 属性,整个事情就完美了(虽然我的渐变还不是那么好),但是你第二次尝试将它附加到它打破了 @ObservedObject 的一个属性,尽管轨道颜色仍然有效,但它永远不会改 rebase 础值。我认为这现在只是一个错误,但更有可能这里有一些东西需要修复。

struct RedscaleSlider: UIViewRepresentable {
    
    @Binding var value: Double
    
    var min: Double
    var max: Double
    
    class Coordinator: NSObject {
        @Binding var value: Double
        var min: Double
        var max: Double
        
        init(value: Binding<Double>, min: Double = 0, max: Double = 100) {
           _value = value
            self.min = min
            self.max = max
        }
        
        @objc func valueChanged(_ sender: UISlider) {
            self.value = Double(sender.value)
            sender.minimumTrackTintColor = green_to_red_gradient(value: (Double(sender.value) - min) / (max - min)).into_UIKit_color()
        }
    }
    
    var thumb_color: UIColor = .white
    var track_color: UIColor = .systemBlue
    
    func makeUIView(context: Context) -> UISlider {
        let slider = UISlider(frame: .zero)
        
        slider.addTarget(
            context.coordinator,
            action: #selector(Coordinator.valueChanged),
            for: .valueChanged
        )
        
        slider.thumbTintColor = thumb_color
        slider.minimumTrackTintColor = track_color
        slider.minimumValue = Float(min)
        slider.maximumValue = Float(max)
        slider.value = Float(value)
        
        return slider
    }
    
    func updateUIView(_ UI_View: UISlider, context: Context) {
        UI_View.value = Float(self.value)
    }
    
    func makeCoordinator() -> RedscaleSlider.Coordinator {
        Coordinator(value: $value, min: self.min, max: self.max)
    }
}

编辑:应该如何使用它的示例:

class ViewModel: ObservableObject {
    @Published var danger_level: Double
}
struct ExampleView: View {
    @ObservedObject var view_model = ViewModel(danger_level: 50)
    
    var body: some View {
        VStack {
            Text(view_model.danger_level.description)
            RedscaleSlider(value: $view_model.danger_level)
            // should update view model just like a Stepper would
        }
    }
}

最佳答案

@Binding 只能用在 View/UIViewRepresentable

不是在 Coordinator 中使用 @Binding 而是切换 init 来接收 init(_ parent: RedscaleSlider) 然后使用 parent.value = Double(sender.value)

import SwiftUI

class RedscaleSliderViewModel : ObservableObject {
    @Published var value : Double = 5
    @Published var danger_level: Double = 7.5

}
struct ParentRedscaleSlider: View{
    //@State var value: Double = 5
    @StateObject var vm = RedscaleSliderViewModel()
    var body: some View {
        VStack{
            Text(vm.danger_level.description)
            RedscaleSlider(value: $vm.danger_level, min: 0, max: 10)
            
        }
    }
}
struct RedscaleSlider: UIViewRepresentable {
    //@EnvironmentObject var vm: RedscaleSliderViewModel
    @Binding var value: Double
    
    var min: Double
    var max: Double
    
    class Coordinator: NSObject {
        var parent: RedscaleSlider
        
        init(_ parent: RedscaleSlider) {
            self.parent = parent
        }
        
        @objc func valueChanged(_ sender: UISlider) {
            let senderVal = Double(sender.value)
            self.parent.value = senderVal
            
            //Missing code
            //sender.minimumTrackTintColor = green_to_red_gradient(value: (Double(sender.value) - min) / (max - min)).into_UIKit_color()
        }
    }
    
    var thumb_color: UIColor = .white
    var track_color: UIColor = .systemBlue
    
    func makeUIView(context: Context) -> UISlider {
        let slider = UISlider(frame: .zero)
        
        slider.addTarget(
            context.coordinator,
            action: #selector(Coordinator.valueChanged),
            for: .valueChanged
        )
        
        slider.thumbTintColor = thumb_color
        slider.minimumTrackTintColor = track_color
        slider.minimumValue = Float(min)
        slider.maximumValue = Float(max)
        slider.value = Float(value)
        
        return slider
    }
    
    func updateUIView(_ UI_View: UISlider, context: Context) {
        UI_View.value = Float(self.value)
    }
    
    func makeCoordinator() -> RedscaleSlider.Coordinator {
        Coordinator(self)
    }
}

struct RedScaleSlider_Previews: PreviewProvider {
    static var previews: some View {
        ParentRedscaleSlider()
    }
}

关于swift - UIViewRepresentable 没有更新绑定(bind)到 ObservedObject 属性?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65208562/

相关文章:

ios - Swift - QR 扫描仪抛出 nil 错误

swift - 类型 '()' 不符合协议(protocol) 'IntegerLiteralConvertible'

Swift - 基于计数器打印和重复消息的程序

ios - SwiftUI 表单无法使用 Spacer() 正确定位

ios - 无法将点击手势识别器添加到 SwiftUI MKMapView UIViewRepresentable

swift - 如何找到给定类型可用的所有属性和方法?

swiftui - 如何在 SwiftUI 下使用异步调用闭包来初始化参数

swift - 使 Button 跨越 VStack

ios - SwiftUI 中的 PencilKit

ios - 如何阻止 SwiftUI 重新加载我通过 UIViewRepresentable 使用的 WKWebView 页面?