使用 AVAudioPlayer 进行 UISlider 更新

Posted

技术标签:

【中文标题】使用 AVAudioPlayer 进行 UISlider 更新【英文标题】:Make UISlider Update with Progress Using AVAudioPlayer 【发布时间】:2018-01-10 07:14:13 【问题描述】:

我正在制作一个简单的音频播放器应用,它允许用户使用 UISlider 更改他们在轨道中的位置。

它没有做什么:滑块不会根据轨道的进度更新。我找到了similar question here,第二个答案是响应AVAudioPlayer——建议使用currentTime 来更新滑块。我想尝试这样做。

这是我的代码:

import UIKit
import AVFoundation

class MusicViewController: UIViewController 

    ....

    @IBOutlet var Slider: UISlider!

    @IBAction func changeAudioTime(_ sender: Any) 
        Slider.maximumValue = Float(audioPlayer.duration)
        audioPlayer.stop()
        audioPlayer.currentTime = TimeInterval(Slider.value)
        audioPlayer.prepareToPlay()
        audioPlayer.play()
    

    func updateSlider()

        Slider.value = Float(audioPlayer.currentTime)
        print("Changing works")
    

第一个函数运行良好——用户可以改变他们的位置。但是,对我来说,第二个功能应该根据 AudioPlayer 的currentTime 更改Slider.value。它不会那样做。

它也没有打印,所以我相信它没有触发。

我是 Swift 的新手,所以我可能会遗漏一些东西。有任何想法吗?

【问题讨论】:

关于 avplayer 概念的 seektotime 怎么样 见sample 【参考方案1】:

测试代码:-

添加定时器变量

var timer: Timer?

在您开始播放音频的函数中:

    slidderrr.value = 0.0
    slidderrr.maximumValue = Float((player?.duration)!)
    audioPlayer.play()
    timer = Timer.scheduledTimer(timeInterval: 0.0001, target: self, selector: #selector(self.updateSlider), userInfo: nil, repeats: true)

当您不想更新滑块时,不要忘记使计时器无效

func stopPlayer() 
    player?.stop()
    timer?.invalidate()
    print("Player and timer stopped")
  

【讨论】:

那么...更新滑块的函数在哪里?????? @ekashking 您可以从 OP 的问题中复制该功能。【参考方案2】:

你试过了吗 func setValue(Float, animated: Bool) Sets the slider’s current value, allowing you to animate the change visually.

比如slider.setValue(index, animated: true)

可以在这里找到

https://developer.apple.com/documentation/uikit/uislider

让我知道这是否有效!

【讨论】:

感谢您的回复,马特。尝试了几件事。首先,我将函数更改为 'Float' 的 .setValue,如下所示:func updateSlider() Slider.setValue(Float, animated: true) 但这给了我一个错误“无法将 Float.type 的值转换为预期的参数”。我试图将此参数更改为一个值,因此再次尝试通过为 AudioPlayer 的currentTime 创建一个变量,如下所示:func updateSlider() let updater = Float(audioPlayer.currentTime) Slider.setValue(updater, animated: true) 。这会运行,但滑块还没有动画。会继续努力。【参考方案3】:

您需要设置CADisplayLink 并在每次调用其选择器时更新滑块的位置。以下是整个AVAudioPlayer-UISlider 绑定的完成方式:

// 1
@IBOutlet weak var slider: UISlider! 
    didSet 
        slider.isContinuous = false

        slider.addTarget(self, action: #selector(didBeginDraggingSlider), for: .touchDown)
        slider.addTarget(self, action: #selector(didEndDraggingSlider), for: .valueChanged)
    


// 2
var player: AVAudioPlayer

// 3
lazy var displayLink: CADisplayLink = CADisplayLink(target: self, selector: #selector(updatePlaybackStatus))

// 4
func startUpdatingPlaybackStatus() 
    displayLink.add(to: .main, forMode: .common)


func stopUpdatingPlaybackStatus() 
    displayLink.invalidate()


// 5
@objc
func updatePlaybackStatus() 
    let playbackProgress = Float(player.currentTime / player.duration)

    slider.setValue(playbackProgress, animated: true)


// 6
@objc
func didBeginDraggingSlider() 
    displayLink.isPaused = true


@objc
func didEndDraggingSlider() 
    let newPosition = player.duration * Double(slider.value)
    player.currentTime = newPosition

    displayLink.isPaused = false

    UISlider 的出口。确保其最小值和最大值分别设置为 0 和 1,并为其 touchDownvalueChanged 事件添加操作,以便在用户分别开始和结束拖动滑块时得到通知。另外,将isContinuous 属性设置为false,这样valueChanged 事件只有在用户释放滑块时才会报告。此设置也可以通过 Interface Builder 和 IBActions 完成; 为了清楚起见,引用了 AVAudioPlayer; 存储 CADisplayLink 实例的属性。由于我们使用self作为目标,所以CADisplayLink的初始化应该在初始化父类之后才能正确引用它。为此,我让它变得懒惰; 开始和停止更新 UI 的方法。您应该在播放状态发生变化时调用它们。 屏幕刷新时调用的方法,更新UI的逻辑存放在这里。 用相当简单的逻辑处理滑块事件的方法 - 当用户开始拖动滑块时暂停显示链接,因此在用户交互期间它的值不会更新;当用户释放滑块时,将音频搜索到所选位置并恢复显示链接。

来源 - my blog post

【讨论】:

以上是关于使用 AVAudioPlayer 进行 UISlider 更新的主要内容,如果未能解决你的问题,请参考以下文章

使用 AVAudioplayer 进行流式传输

AVAudioPlayer 在进行 WebRTC 音频通话时以非常低的音量播放声音

为啥 AVAudioPlayer 没有响应?

iPhone SDK:如何使用 AVAudioPlayer 标准化音频播放?

AVPlayer 与 AVAudioPlayer

从 plist(NSArray) 中挑选歌曲并使用 AVAudioPlayer 播放?