更新 AVPlayer 时 UISlider 跳转

Bar*_*zyk 5 uislider ios avplayer swift

我尝试使用 UISlider 实现简单的播放器来指示当前音频文件的时间。

在此输入图像描述

在代码中我添加了两个观察者:

    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)
    }
Run Code Online (Sandbox Code Playgroud)

具有一个私有函数:

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)
}
Run Code Online (Sandbox Code Playgroud)

当音频播放时,一切都很好,滑块也几乎更新了。当我在播放音频时尝试手动移动滑块时,就会出现问题,然后滑块会跳跃。为什么?

更新

其实我知道为什么。因为我更新了两次:手动更新和玩家观察者更新,但如何防止这种行为?

sta*_*Man 6

解决此问题的一种简单方法是防止在触摸滑块时addPeriodicTimeObserver调用。self?.updateSlider(with: time)

UISlider这可以通过s属性确定isTracking

正在追踪

一个布尔值,指示控件当前是否正在跟踪触摸事件。

当跟踪触摸事件时,控件会将此属性的值设置为 true。当跟踪结束或因任何原因取消时,它会将此属性设置为 false。

参考:https://developer.apple.com/documentation/uikit/uicontrol/1618210-itracking

这存在于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)
}
Run Code Online (Sandbox Code Playgroud)

通用示例:

@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
}
Run Code Online (Sandbox Code Playgroud)

我确信还有其他(更好)的方法,但我在 RxSwift 中还没有做太多事情。
我希望现在这已经足够好了。