swift仿刻apple音樂播放器 ,來點音樂
Published in
10 min readApr 3, 2020
練習到function,Array,AVPlayer,AVPlayerItem,addPeriodicTimeObserver,removeTimeObserver
主要參考同學Lucas,省掉了一些卡關時間,
花最多時間的在取得音樂正在播放的秒數與音樂總秒數,
這邊卡了好幾個小時,
抓出音樂秒數之後,還要轉成 分:秒 格式,要除60之後取餘數%
說是這樣說拉…目前還不想做,還有一些細節,改天再來處理。
程式碼如下
import UIKit
import AVFoundation
class ViewController: UIViewController {
//var player = AVPlayer()
var player: AVPlayer!
//偵測歌曲目前播放所需的宣告
var playerItem: AVPlayerItem?
var timeObserverToken: Any?
var playIndex = 0
var songData = [
album(albumname: "Back In Black", albumimage: "1", singer: "ACDC", songname: "Back In Black"),
album(albumname: "Back In Black", albumimage: "2", singer: "ACDC", songname: "Boogie Man"),
album(albumname: "Back In Black", albumimage: "3", singer: "ACDC", songname: "Girls Got Rhythm"),
album(albumname: "Back In Black", albumimage: "4", singer: "ACDC", songname: "Hard as a Rock"),
album(albumname: "Back In Black", albumimage: "5", singer: "ACDC", songname: "Hells Bells"),
album(albumname: "Back In Black", albumimage: "6", singer: "ACDC", songname: "Shoot to Thrill"),
album(albumname: "Back In Black", albumimage: "7", singer: "ACDC", songname: "Shot Down in Flames"),
album(albumname: "Back In Black", albumimage: "8", singer: "ACDC", songname: "Thunderstruck"),
]
func playinformation(){
songText.text = songData[playIndex].songname
singerText.text = songData[playIndex].singer
}
func playmusic(){
if playIndex < songData.count{
//解決上一首變成-1會找不到陣列資料的問題
if playIndex < 0{
playIndex = songData.count - 1
}
if let songurl = Bundle.main.url(forResource:songData[playIndex].songname, withExtension: "mp4"){
player = AVPlayer(url: songurl)
playerItem = AVPlayerItem(url: songurl)
}
cover.image = UIImage(named: songData[playIndex].albumimage)
addPeriodicTimeObserver()
progress.value = 0
player.play()
}else{
playIndex = 0
playmusic()
}
}
//添加定期時間觀察者
func addPeriodicTimeObserver() {
// 每半秒查看
let timeScale = CMTimeScale(NSEC_PER_SEC)
let time = CMTime(seconds: 0.5, preferredTimescale: timeScale)
timeObserverToken = player.addPeriodicTimeObserver(forInterval: time,queue: .main) {[weak self] time in
// update player transport UI
let songcurrent = self!.player.currentTime().seconds
let songcurrentInt = Int(songcurrent)
self!.currentText.text = "\(songcurrentInt)"
let duration = self!.playerItem?.asset.duration
let songtotal = CMTimeGetSeconds(duration!)
let songtotalInt = Int(songtotal)
self!.totalText.text = "\(songtotalInt)"
let currenttotal:Float = Float(songcurrent / songtotal)
self!.progress.value = currenttotal
}
}
//移除定期時間觀察者
func removePeriodicTimeObserver() {
if let timeObserverToken = timeObserverToken {
player.removeTimeObserver(timeObserverToken)
self.timeObserverToken = nil
}
}
@IBOutlet weak var cover: UIImageView!
@IBOutlet weak var cover_shadow: UIView!
@IBOutlet weak var playButton: UIButton!
@IBOutlet weak var nextButton: UIButton!
@IBOutlet weak var preButton: UIButton!
@IBOutlet weak var songText: UILabel!
@IBOutlet weak var singerText: UILabel!
@IBOutlet weak var volumeShow: UISlider!
@IBOutlet weak var progress: UISlider!
@IBOutlet weak var totalText: UILabel!
@IBOutlet weak var currentText: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
cover_shadow.layer.shadowOpacity = 0.2
cover_shadow.layer.cornerRadius = 7
cover.clipsToBounds = true
cover.layer.cornerRadius = 7
cover.image = UIImage(named: songData[playIndex].albumimage)
playButton.setImage(UIImage(systemName: "play.fill"), for: .normal)
playmusic()
player.pause()
playinformation()
volumeShow.value = 0.5
// 播完後,繼續播下一首
NotificationCenter.default.addObserver(forName: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: nil, queue: .main) { (_) in
// 移除監聽
self.removePeriodicTimeObserver()
self.playIndex += 1
self.playmusic()
}
}
@IBAction func playbtn(_ sender: Any) {
playinformation()
if player.rate == 0 {
playButton.setImage(UIImage(systemName: "pause.fill"), for: .normal)
player.play()
}else {
playButton.setImage(UIImage(systemName: "play.fill"), for: .normal)
player.pause()
}
}
@IBAction func nextbtn(_ sender: Any) {
playIndex += 1
playmusic()
player.play()
playinformation()
}
@IBAction func prebtn(_ sender: Any) {
playIndex -= 1
playmusic()
player.play()
playinformation()
}
@IBAction func volumeBtn(_ sender: Any) {
let volume = volumeShow.value
player.volume = volume
}
@IBAction func progressBtn(_ sender: Any) {
let songcurrent = progress.value
let duration = self.playerItem?.asset.duration
let songtotal = CMTimeGetSeconds(duration!)
let songtotalFloat = Float(songtotal)
let songhahqa = Int(songtotalFloat * songcurrent)
let time = CMTime(value: CMTimeValue(songhahqa), timescale: 1)
player.seek(to: time)
}
}