更新值时 UISlider 卡顿

问题描述 投票:0回答:4

我正在创建一个音频播放器并使用

UISlider
实时更新音频的播放时间。我决定使用一个周期性时间观察器来做到这一点:

player.addPeriodicTimeObserver(forInterval: CMTime(seconds: 1, preferredTimescale: CMTimeScale(NSEC_PER_SEC)), queue: .main) { time in
    slider.setValue(Float(time.seconds), animated: false)
}

这是一个好的开始,但是我遇到了一个问题,当我试图用滑块更改/寻找时间时,它会触发(可以理解),所以我将其更改为:

player.addPeriodicTimeObserver(forInterval: CMTime(seconds: 1, preferredTimescale: CMTimeScale(NSEC_PER_SEC)), queue: .main) { time in
    if !slider.isHighlighted {
        slider.setValue(Float(time.seconds), animated: false)
    }
}

这很棒,但我面临的最后一个问题是,当我放开滑块时,它似乎会快速将滑块值设置回设置新值之前的状态,然后快速修复自身。请看下面的视觉效果:

再次澄清一下,它像那样口吃我一松手,而不是在我试图滑动的时候

swift uislider
4个回答
2
投票

这看起来像

PeriodicTimeObserver
正在发送正确的值,但直到之后搜索才真正完成,这导致了卡顿。我建议你有一个标志,可以在要求观察者更新任何值之前确定搜索是否已完成。

我建议你做这样的事情,因为它消除了删除听众的需要,而是忽略了。可能不是最好的解决方案,但它会完成这项工作。

var isSeeking = false

player.addPeriodicTimeObserver(forInterval: CMTime(seconds: 1, preferredTimescale: CMTimeScale(NSEC_PER_SEC)), queue: .main) { time in
    if !isSeeking {
        slider.setValue(Float(time.seconds), animated: false)
    }
}

func seekToTime(_ time: CMTime) {
    isSeeking = true

    player.seek(to: time, completionHandler: { [unowned self] (completed) in
        if completed {
            isSeeking = false
        }
    })
}

0
投票

尝试从滑块监听触摸事件。并在每个 - touchBegin/touchEnd 事件上删除/添加观察者。这样您在手动更改时间时将不会收到来自播放器的更新。 查看有关如何保留观察令牌并在需要时将其删除的文档。 https://developer.apple.com/documentation/avfoundation/avplayer/1385829-addperiodictimeobserver 一些有用的 SO 链接 - 在 iOS AVPlayer 中,addPeriodicTimeObserverForInterval 似乎丢失了


0
投票

试试这个,似乎 timeObserver 在搜索之前和搜索之后被触发,那些不需要的更新总是有不同的时间尺度

    let preferredTimescale = CMTimeScale(NSEC_PER_SEC)
    player.addPeriodicTimeObserver(forInterval: CMTime(seconds: 1, preferredTimescale: preferredTimescale), queue: .main) { time in
        if time.timescale == preferredTimescale, time.flags == .valid {
            slider.setValue(Float(time.seconds), animated: false)
        }
    }

0
投票

欧文的答案是正确的,需要时间来寻找,并且在寻找时你不应该更新滑块。

你也应该在

slider.isTracking
而不是
slider.isHighlighted
上测试:

player.addPeriodicTimeObserver(forInterval: CMTime(seconds: 1, preferredTimescale: CMTimeScale(NSEC_PER_SEC)), queue: .main) { time in
    if !isSeeking && !slider.isTracking {
        slider.setValue(Float(time.seconds), animated: false)
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.