2

我有一个具有自定义事件的自定义 UIKit 控件。有谁知道如何使用 Combine 框架将此事件公开给 SwiftUI?

我可以使用 Combine 的 UIViewRepresentable 呈现控件,但找不到将自定义事件或内部 UIKit 事件更改的值公开给 SwiftUI 的方法。

下面是这个问题的一个具体例子:

我正在使用这个自定义 UIKit 滑块控件(因为它支持多个旋钮/值):

https://github.com/yonat/MultiSlider

它有一个更新当前值的 sliderChanged 事件。如何使用 Combine 将此值公开给 SwiftUI?

我不能简单地传入@ObservedObject,因为 UIViewRepresentable 不允许这样做。我也无法从事件处理程序更新 @Binding 变量,因为 UIKit 事件处理程序标有 @objc 并且它不喜欢它。

这似乎是一个非常常见的用例。我希望苹果有一个标准的解决方案。但是,我根本找不到真正适用于这些类型场景的。我在这里想念什么?

4

2 回答 2

2

我认为,这可以解决您的问题:

final class MultiSliderSwiftUI: UIViewRepresentable {
    private let valueChanged: ([CGFloat]) -> Void

    init(valueChanged: @escaping ([CGFloat]) -> Void) {
        self.valueChanged = valueChanged
    }

    func makeUIView(context: UIViewRepresentableContext<MultiSliderSwiftUI>) -> MultiSlider {
        let slider = MultiSlider()
        slider.addTarget(self, action: #selector(sliderChanged(_:)), for: .valueChanged)

        return slider
    }

    func updateUIView(_ uiView: MultiSlider, context: UIViewRepresentableContext<MultiSliderSwiftUI>) {

    }

    @objc func sliderChanged(_ slider: MultiSlider) {
        valueChanged(slider.value)
    }
}

如果你不喜欢final class为 SwiftUI 视图创建,你可以这样做:

struct MultiSliderSwiftUI: UIViewRepresentable {
    private let events: MultiSliderEvents

    init(valueChanged: @escaping ([CGFloat]) -> Void) {
        events = MultiSliderEvents(valueChanged: valueChanged)
    }

    func makeUIView(context: UIViewRepresentableContext<MultiSliderSwiftUI>) -> MultiSlider {
        let slider = MultiSlider()
        events.addEvents(for: slider)

        return slider
    }

    func updateUIView(_ uiView: MultiSlider, context: UIViewRepresentableContext<MultiSliderSwiftUI>) {

    }
}

class MultiSliderEvents {
    private let valueChanged: ([CGFloat]) -> Void

    init(valueChanged: @escaping ([CGFloat]) -> Void) {
        self.valueChanged = valueChanged
    }

    func addEvents(for slider: MultiSlider) {
        slider.addTarget(self, action: #selector(sliderChanged(_:)), for: .valueChanged)
    }

    @objc func sliderChanged(_ slider: MultiSlider) {
        valueChanged(slider.value)
    }
}

在这两种方式中,您都可以使用它MultiSliderSwiftUI,例如Button

MultiSliderSwiftUI { value in
    print("\(value)")
}
于 2019-10-07T11:07:06.960 回答
1

请尝试分支中的MultiValueSliderswiftui告诉我它是否适合您。
示例用法:MultiSliderDemo

(我是包作者)

于 2019-10-07T11:56:41.870 回答