为 AVPlayer 更新时 UISlider 跳转

Posted

技术标签:

【中文标题】为 AVPlayer 更新时 UISlider 跳转【英文标题】:UISlider jumps when updating for AVPlayer 【发布时间】:2019-03-08 08:17:18 【问题描述】:

我尝试使用 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)
    

只有一个私有函数:

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)

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

更新:

我知道为什么。因为我更新了两次:手动和玩家观察者,但是如何防止这种行为?我不知道;)请帮忙。

【问题讨论】:

看到这个寻求帮助:***.com/questions/43062870/… addPeriodicTimeObserver 块中的 case 处理如何在滑块被触摸时立即返回? @staticVoidMan 您希望如何实现它?;) 请回答您的想法,我会尝试。 @BartłomiejSemańczyk 好吧,基本的想法是防止滑块在被触摸/移动时更新。我会写一个示例:) 【参考方案1】:

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

这可以通过UISliders isTracking 属性来确定:

是跟踪

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

在跟踪触摸事件的过程中,控件设置 此属性的值为 true。当跟踪结束或被取消时 任何原因,它都会将此属性设置为 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 方面做得不多(还)。 我希望这已经足够好了。

【讨论】:

以上是关于为 AVPlayer 更新时 UISlider 跳转的主要内容,如果未能解决你的问题,请参考以下文章

UISlider 不能与 AVPlayer 一起正常工作

Objective-c,AVPlayer 中的 UISlider 无法正常工作,在洗涤器之后

UISlider Swift 的 AVPlayer 进度

UISlider 的 Avplayer 问题

具有缓冲进度的 UISlider - AVPlayer

AVPlayer seekToTime 不正确使用 UISlider