Swift — 做個播放器吧(功能篇-1)
上一次的文章我們規劃及設計好我們的播放器畫面了,那這次我們要來實作播放器的功能了,如果還沒看過的可以先瀏覽一次。
在建立音樂播放器之前,首先我們必須先導入 AVFoundation,可以想像它是一個用來播放視頻媒體的 Framework,可以在我們 APP 中建立強大媒體功能。所以我們必須先 import AVFoundation
import AVFoundation
之後就可以開始慢慢建立我們的播放器了
建立播放器
如果只要單純放音訊的播放器,我們就使用 AVAuidoPlayer,如果你想同時可以播放影片和音訊的話,可以使用 AVPlayer,這邊因為部分原因,所以我使用 AVPlayer 來製作:
var audioPlayer:AVPlayer?
然後為了抓到我們歌曲的資訊,我們必須要在宣告一個屬性,之後我們會需要抓取歌曲進度或總長度等等:
var playerItem:AVPlayerItem?
之後我們需要在 viewDidLoad 下面增加這幾行計算我們歌曲的長度,以及:
func updatePlayerUI() {// 抓取 playItem 的 duration
let duration = playerItem!.asset.duration// 把 duration 轉為我們歌曲的總時間(秒數)。
let seconds = CMTimeGetSeconds(duration)// 把我們的歌曲總時長顯示到我們的 Label 上。
songLengthLabel.text = formatConversion(time: seconds)
songProgressSlider!.minimumValue = 0// 更新 Slider 的 maximumValue。
songProgressSlider!.maximumValue = Float(seconds)// 這裡看個人需求,如果想要拖動後才更新進度,那就設為 false;如果想要直接更新就設為 true,預設為 true。
songProgressSlider!.isContinuous = true}
這時你會發現,歌曲的格式是錯誤的,那我上面的 formatConversion(time:) 是做什麼呢?其實他就是我自定義出來轉換格式的方法,讓我們可以把秒數轉換成幾分幾秒的格式,最後輸出成一個 String 直接顯示在 Label 上:
func formatConversion(time:Float64) -> String {let songLength = Int(time)
let minutes = Int(songLength / 60) // 求 songLength 的商,為分鐘數
let seconds = Int(songLength % 60) // 求 songLength 的餘數,為秒數var time = ""if minutes < 10 {
time = "0\(minutes):"
} else {
time = "\(minutes)"
}if seconds < 10 {
time += "0\(seconds)"
} else {
time += "\(seconds)"
} return time}
這邊總長度算完了,接下來我們需要計算的是當前時間,這邊我們需要在 viewDidLoad 建立一個 Observer 來觀察歌曲的播放進度,更新我們的 Slider 數值以及歌曲當前時間的 Label:
audioPlayer?.addPeriodicTimeObserver(forInterval: CMTimeMake(1, 1), queue: DispatchQueue.main, using: { (CMTime) inif self.audioPlayer!.currentItem?.status == .readyToPlay {let currentTime = CMTimeGetSeconds(self.audioPlayer!.currentTime())
self.songProgressSlider.value = Float(currentTime)
self.currentTimeLabel.text = self.formatConversion(time: currentTime) }
})
別忘了這邊的時間也需要套用我們自訂的轉換格式的方法。
接下來我們需要來製作我們最重要的一個步驟了,就是我們播放音樂的按鈕,別忘了我們的播放鍵也同時是我們的暫停鍵,所以我們必須要知道是否正在播放,我們有兩種方法來設定:
- 設定 isPlaying 變數
我們可以自己設定一個變數,當播放時 isPlaying 就從 false 轉為 true,播放器則開始播放,反之則是,isPlaying 轉為 false 停止播放:
@IBAction func playAndPause(_ sender: UIButton) { if isPlaying == false { playButton.setImage(UIImage(named: "icons8-pause"), for: UIControlState.normal)
isPlaying = true
audioPlayer?.play()
} else { playButton.setImage(UIImage(named: "icons8-play"), for: UIControlState.normal)
isPlaying = false
audioPlayer?.pause()
}}
2. 根據 rate 速率來判斷歌曲是否停止
我們可以根據播放的 rate ( 播放速率 ),來判斷他是否正在播放,這種方式可能也比較顧及全面,畢竟如果有其他方式不小心播放了音樂,也能透過這種方式判斷音樂是否正在播放:
@IBAction func playAndPause(_ sender: UIButton) {if audioPlayer?.rate == 0 { playButton.setImage(UIImage(named: "icons8-pause"), for: UIControlState.normal)
audioPlayer?.play() } else { playButton.setImage(UIImage(named: "icons8-play"), for: UIControlState.normal)
audioPlayer?.pause() }}
這時我們的音樂應該可以正常播放了,接下來就是要來控制我們的 Slider 進度條了,所以我們讓 Slider 與程式碼連結, Action 選擇 Value Change:
@IBAction func changeCurrentTime(_ sender: UISlider) { let seconds = Int64(songProgressSlider.value)
let targetTime:CMTime = CMTimeMake(seconds, 1) // 將當前設置時間設為播放時間
audioPlayer?.seek(to: targetTime)}
這樣子我們的播放器的基本功能就算完成了。(大灑花
來看一下目前的 Demo 吧!
本次參考文獻: