Предоставление пользовательских пользовательских событий UIKit из пользовательских элементов управления UIKit в SwiftUI - PullRequest
1 голос
/ 07 октября 2019

У меня есть пользовательский элемент управления UIKit, который имеет пользовательское событие. Кто-нибудь знает, как представить это событие SwiftUI, используя платформу Combine?

Я могу отобразить элемент управления, используя UIViewRepresentable Combine, но не могу найти способ представить пользовательские события или значения, измененные внутренними событиями UIKit, SwiftUI.

Вот конкретный пример этой проблемы:

Я использую этот пользовательский элемент управления ползунком UIKit (поскольку он поддерживает несколько регуляторов / значений):

https://github.com/yonat/MultiSlider

У него есть событие sliderChanged, которое обновляет текущее значение. Как мне выставить это значение SwiftUI с помощью Combine?

Я не могу просто передать @ObservedObject, потому что UIViewRepresentable не позволяет этого. Я также не могу обновить переменную @Binding из обработчика событий, потому что обработчики событий UIKit помечены @objc, и это не нравится.

Кажется, это очень распространенный случай использования. Я ожидал, что у Apple будет стандартное решение для этого. Тем не менее, я просто не могу найти тот, который на самом деле работает для этих типов сценариев. Что мне здесь не хватает?

Ответы [ 2 ]

1 голос
/ 07 октября 2019

Попробуйте MultiValueSlider из ветви swiftui и скажите мне, работает ли он для вас.
Пример использования: MultiSliderDemo .

(IЯ автор пакета)

1 голос
/ 07 октября 2019

Я думаю, что это может быть решением вашей проблемы:

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