使用 AVAudioPlayer 使 UISlider 随进度更新
Make UISlider Update with Progress Using AVAudioPlayer
我正在制作一个简单的音频播放器应用程序,它允许用户使用 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 的新手,所以我可能遗漏了一些东西。有任何想法吗?
你试过了吗
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
如果可行,请告诉我!
测试代码:-
添加定时器变量
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")
}
您需要设置 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
}
- UI滑块的出口。确保其最小值和最大值分别设置为 0 和 1,并为其
touchDown
和 valueChanged
事件添加操作,以便在用户分别开始和结束拖动滑块时得到通知。另外,将one的isContinuous
属性设置为false
,这样只有当用户释放滑块时才会报告valueChanged
事件。此设置也可以使用 Interface Builder 和 IBActions 完成;
- 为了清晰起见,引用了 AVAudioPlayer;
- A 属性 存储 CADisplayLink 实例。由于我们使用
self
作为目标,CADisplayLink的初始化应该在初始化父class之后进行,这样才能正确引用它。为此,我让它变懒了;
- 启动和停止更新 UI 的方法。您应该在播放状态发生变化时调用它们。
- 屏幕刷新时调用的方法,更新UI的逻辑存储在这里。
- 使用相当简单的逻辑处理滑块事件的方法 - 当用户开始拖动滑块时暂停显示 link,因此它的值在用户交互期间不会更新;将音频搜索到所选位置并在用户释放滑块时恢复显示 link。
来源 - my blog post
我正在制作一个简单的音频播放器应用程序,它允许用户使用 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 的新手,所以我可能遗漏了一些东西。有任何想法吗?
你试过了吗
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
如果可行,请告诉我!
测试代码:-
添加定时器变量
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")
}
您需要设置 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
}
- UI滑块的出口。确保其最小值和最大值分别设置为 0 和 1,并为其
touchDown
和valueChanged
事件添加操作,以便在用户分别开始和结束拖动滑块时得到通知。另外,将one的isContinuous
属性设置为false
,这样只有当用户释放滑块时才会报告valueChanged
事件。此设置也可以使用 Interface Builder 和 IBActions 完成; - 为了清晰起见,引用了 AVAudioPlayer;
- A 属性 存储 CADisplayLink 实例。由于我们使用
self
作为目标,CADisplayLink的初始化应该在初始化父class之后进行,这样才能正确引用它。为此,我让它变懒了; - 启动和停止更新 UI 的方法。您应该在播放状态发生变化时调用它们。
- 屏幕刷新时调用的方法,更新UI的逻辑存储在这里。
- 使用相当简单的逻辑处理滑块事件的方法 - 当用户开始拖动滑块时暂停显示 link,因此它的值在用户交互期间不会更新;将音频搜索到所选位置并在用户释放滑块时恢复显示 link。
来源 - my blog post