仿 iOS Music App (基本題)

播放, 暫停, 上 / 下首, 調整音量

--

成品:Gif / 影片,因 #FreeBritney 朋友提議選我們懶妮做主題

▲這幾年西音全是莫名怪 Rap 便聽日文為主,這次回歸馬上陷音樂漩渦
▲我們那年代真的超全盛爆多 icon 的啦!一回味半天就掰了😅
▲最後精選和懶妮合演 / 作過 4 大咖 / 金曲及她出道曲
▲本想挑戰進階題但搞不懂 addPeriodicTimeObserver() 只好放棄
▲沒音樂時間顯示和 Slider 軌跡有夠怪還不能拉區段,但我太嫩沒辦法
▲音樂時間等程式很多也很難,看蘋果 Documentation 時會瞬間變文盲

再多放個懶妮和娜姐合作曲😍

前置作業

▲找歌與專輯封面,我有 CD 但 Mac 沒光碟機無法直接放檔案也是好笑
▲ Storyboard 版面配置,因只有基本題其他功能 (圖) 就先刪掉不放
▲ iphone 原圖背景是封面其中幾色漸層,但彼得說那要另套件再寫程式
▲背景一樣放封面選擇毛玻璃效果 Visual Effect View with Blur (Library)
▲ button 怕之後做進階題有需要,皆把圖放 background 非一般 image

有音樂所以加入 AVFoundation 函式庫 (framework)

import AVFoundation

新增 Swift File struct定義 Single 型別

struct Single {
let song: String!
let singer: String!
let albumCover: String!
}

拉 IBOutlet

@IBOutlet weak var backgroundImageView: UIImageView!
@IBOutlet weak var albumCoverImageView: UIImageView!
@IBOutlet weak var songLabel: UILabel!
@IBOutlet weak var singerLabel: UILabel!
@IBOutlet weak var volumeSlider: UISlider!@IBOutlet weak var playPauseButton: UIButton!

宣告:單曲資訊 Array, AVPlayer 型別的 property player

var singles = [Single]()
var index = 0
var player = AVPlayer()

初始畫面:封面圓角,Slider 指標圖 (自己做小圓球),單曲各資訊

override func viewDidLoad() {
super.viewDidLoad()
albumCoverImageView.layer.cornerRadius = 13 volumeSlider.setThumbImage(UIImage(named: “thumb2”), for:
.normal)
singles = [
Single(song: “…Baby One More Time”, singer: “Britney
Spears”,albumCover: “britney”),
Single(song: “The Way You Make Me Feel”, singer: “Michael
Jackson
”, albumCover: “MJ”),
Single(song: “Hollywood”, singer: “Madonna”, albumCover:
madonna”),
Single(song: “I Want It That Way”, singer: “Backstreet
Boys
”,albumCover: “backstreet boys”),
Single(song: “S&M”, singer: “Rihanna”, albumCover:
rihanna”)
]
}

定義 playMusic():單曲資訊 / 播放歌曲依 index 改變,按鍵為 pause

func playMusic(){
backgroundImageView.image = UIImage(named:
singles[index].albumCover)
albumCoverImageView.image = UIImage(named:
singles[index].albumCover)
songLabel.text = singles[index].song
singerLabel.text = singles[index].singer
let fileUrl = Bundle.main.url(forResource: singles[index].singer,
withExtension: “mp3”)!
let playerItem = AVPlayerItem(url: fileUrl)

player.replaceCurrentItem(with: playerItem)
player.play()
playPauseButton.setBackgroundImage(UIImage(systemName:
pause.fill”), for: .normal)
}

拉 IBAction

@IBAction func playNPause(_ sender: Any) {
}
@IBAction func nextSong(_ sender: Any) {
}
@IBAction func PreviousSong(_ sender: Any) {
}
@IBAction func changeVolume(_ sender: UISlider) {
}

播放 / 暫停

▲首個條件一直想不出來直到彼得幫忙,player.currentItem 我記得你了
▲除 player.rate = 0 也可用 player.timeControlStatus = .paused / .playing
▲續播不用 player.play() 也可用 player.seek(to: player.currentTime())
▲有 player.play() 當然也有 player.pause(),1 個播 1 個停

@IBAction func playNPause(_ sender: Any) {
if player.currentItem == nil {
playMusic()
} else if player.rate == 0 {
playPauseButton.setBackgroundImage(UIImage(systemName:
pause.fill”), for: .normal)
player.play() } else {
playPauseButton.setBackgroundImage(UIImage(systemName:
play.fill”), for: .normal)
player.pause()
}
}

下一首:簡單寫法是使用餘數,也可用下面上一首類似寫法

@IBAction func nextSong(_ sender: Any) {
index = (index + 1) % singles.count
playMusic()}

上一首:注意 Array.count 是總數,和陣列裡編號不一樣,所以要 -1

@IBAction func PreviousSong(_ sender: Any) {
index -= 1
if index < 0 {
index = singles.count — 1

playMusic()
} else {
playMusic()
}
}

調整音量:2 種方法

▲直接用 slider value 代入,手法粗糙

@IBAction func changeVolume(_ sender: UISlider) {

player.volume = sender.value
}

▲實際調整系統音量 (下為彼得例子)
➞先加 import MediaPlayer,然後在畫面上加入 MPVolumeView
➞只能在實機測試,模擬器無法

let volumeView = MPVolumeView(frame: CGRect(x: 10, y: 100, width: 300, height: 40))view.addSubview(volumeView)

完整程式碼:上半部為 Single (struct),下半部為 ViewController

參考來源

--

--