UISlider скачет при обновлении для AVPlayer - PullRequest
3 голосов
/ 08 марта 2019

Я пытаюсь реализовать простой плеер с UISlider, чтобы указать, в какое время находится текущий аудиофайл.

enter image description here

В коде я добавил двух наблюдателей:

    slider.rx.value.subscribe(onNext: { value in
        let totalTime = Float(CMTimeGetSeconds(self.player.currentItem!.duration))
        let seconds = value * totalTime
        let time = CMTime(seconds: Double(seconds), preferredTimescale: CMTimeScale(NSEC_PER_SEC))
        self.player.seek(to: time)
        }).disposed(by: bag)
    let interval = CMTime(seconds: 0.1, preferredTimescale: CMTimeScale(NSEC_PER_SEC))
    player.addPeriodicTimeObserver(forInterval: interval, queue: nil) { [weak self] time in
        self?.updateSlider(with: time)
    }

с одной частной функцией:

private func updateSlider(with time: CMTime) {
    let currentTime = CMTimeGetSeconds(time)
    var totalTime = CMTimeGetSeconds(player.currentItem!.duration)
    if totalTime.isNaN {
        totalTime = 0
    }
    startLabel.text = Int(currentTime).descriptiveDuration
    endLabel.text = Int(totalTime).descriptiveDuration
    slider.value = Float(currentTime / totalTime)
}

Когда воспроизводится звук, все в порядке, и слайдер в значительной степени обновляется. Проблема возникает, когда я пытаюсь переместить ползунок вручную во время воспроизведения звука, затем он прыгает. Почему?

UPDATE:

Я знаю, почему на самом деле. Потому что я обновляю его дважды: вручную и от игрока-наблюдателя, но как предотвратить такое поведение? Понятия не имею;) Пожалуйста, помогите.

1 Ответ

2 голосов
/ 08 марта 2019

Один простой способ сделать это - запретить addPeriodicTimeObserver вызывать self?.updateSlider(with: time) при касании ползунка.

Это можно определить с помощью свойства UISlider s isTracking:

isTracking

Логическое значение, указывающее, отслеживает ли в данный момент элемент управления события касания.

Во время отслеживания события касания элемент управления устанавливает значениеэтого свойства к истине.Когда отслеживание заканчивается или отменяется по любой причине, оно устанавливает для этого свойства значение false.

Ссылка: https://developer.apple.com/documentation/uikit/uicontrol/1618210-istracking

Это присутствует во всех элементах UIControl, которыеВы можете использовать это следующим образом:

player.addPeriodicTimeObserver(forInterval: interval, queue: nil) { [weak self] time in
    //check if slider is being touched/tracked
    guard self?.slider.isTracking == false else { return }

    //if slider is not being touched, then update the slider from here
    self?.updateSlider(with: time)
}

Общий пример:

@IBOutlet var slider: UISlider!
//...
func startSlider() {
    slider.value = 0
    slider.maximumValue = 10

    Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true) { [weak self] (timer) in
        print("Slider at: \(self?.slider.value)")
        guard self?.slider.isTracking == false else { return }
        self?.updateSlider(to: self!.slider.value + 0.1)
    }
}

private func updateSlider(to value: Float) {
    slider.value = value
}

Я уверен, что есть и другие (лучшие) способы выходано я еще ничего не сделал в RxSwift (пока).
Надеюсь, этого пока достаточно.

...