Swift — 做個播放器吧(功能篇-1)

Jeremy Xue
7 min readJun 11, 2018

--

上一次的文章我們規劃及設計好我們的播放器畫面了,那這次我們要來實作播放器的功能了,如果還沒看過的可以先瀏覽一次。

在建立音樂播放器之前,首先我們必須先導入 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)
}
})

別忘了這邊的時間也需要套用我們自訂的轉換格式的方法。

接下來我們需要來製作我們最重要的一個步驟了,就是我們播放音樂的按鈕,別忘了我們的播放鍵也同時是我們的暫停鍵,所以我們必須要知道是否正在播放,我們有兩種方法來設定:

  1. 設定 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 吧!

本次參考文獻:

--

--