Intento implementar un reproductor simple con UISlider para indicar a qué hora está el archivo de audio actual.
En el código he añadido dos observadores:
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) }con una función privada:
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) }Cuando se reproduce el audio, todo está bien y el control deslizante está prácticamente actualizado. El problema ocurre cuando trato de mover el control deslizante manualmente mientras se reproduce el audio, luego salta. ¿Por qué?
ACTUALIZAR:
Sé por qué en realidad. Porque lo actualizo dos veces: manualmente y desde el observador del jugador, pero ¿cómo evitar este comportamiento? No tengo ni idea;) por favor, ayuda.
Una forma sencilla de hacerlo sería evitar que addPeriodicTimeObserver llame a self?.updateSlider(with: time) cuando se toca el control deslizante.
Esto se puede determinar a través de la propiedad UISlider de isTracking :
esSeguimiento
Un valor booleano que indica si el control está actualmente rastreando eventos táctiles.
Mientras se realiza el seguimiento de un evento táctil, el control establece el valor de esta propiedad en verdadero. Cuando el seguimiento finaliza o se cancela por cualquier motivo, establece esta propiedad en falso.
Ref: https://developer.apple.com/documentation/uikit/uicontrol/1618210-istracking
Esto está presente en todos los elementos de UIControl que puede usar de esta manera:
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 } Estoy seguro de que hay otras formas (mejores) pero no he hecho mucho en RxSwift (todavía).
Espero que esto sea lo suficientemente bueno por ahora.