【问题标题】:Exposing custom custom UIKit events from custom UIKit controls to SwiftUI将自定义 UIKit 事件从自定义 UIKit 控件公开到 SwiftUI
【发布时间】:2019-10-07 10:33:45
【问题描述】:

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

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

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

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

https://github.com/yonat/MultiSlider

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

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

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

【问题讨论】:

    标签: event-handling uikit swiftui combine


    【解决方案1】:

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

    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)
        }
    }
    

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

    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)")
    }
    

    【讨论】:

    • 感谢您的回复!非常感谢!
    【解决方案2】:

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

    (我是包作者)

    【讨论】:

    • 感谢您的回复!非常感谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-07-17
    • 1970-01-01
    • 1970-01-01
    • 2021-03-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多