音頻視頻播放器
Published in
10 min readNov 8, 2020
@IBOutlet var playerButton: [UIButton]!@IBOutlet weak var slider: UISlider!@IBOutlet weak var maxLabel: UILabel!@IBOutlet weak var minLabel: UILabel!@IBOutlet weak var ImageView: UIImageView!var playerLoop:AVPlayerLooper? //沒有初始值的存儲屬性“videoLoop”會阻止合成初始化程序,故要加 Optional ?var playerItem:AVPlayerItem?var queuePlayer = AVQueuePlayer()let playerItemUrl = ["Realize","紅蓮華","神之塔"]let songImage = ["從零開始","鬼滅之刃","神之塔"]var number = 0var notification:Any?
override func viewDidLoad() {super.viewDidLoad()//預設初始音樂switchSong(arrayNumber: number)//觀察播放進度queuePlayer.addPeriodicTimeObserver(forInterval: CMTime(value: 1, timescale: 1), queue: DispatchQueue.main) { [self] (CMTime) inif queuePlayer.timeControlStatus == .playing{playerButton[2].setTitle("⏸", for: UIControl.State.normal)/*可替換寫成let currentTime = CMTimeGetSeconds(queuePlayer.currentTime())*/let currentTime = Float64(queuePlayer.currentTime().seconds) //Float64 = Doubleslider.value = Float(currentTime)minLabel.text = caculateTime(seconds: currentTime)}else{playerButton[2].setTitle("▶️", for: UIControl.State.normal)}}}
@IBSegueAction func showVideo(_ coder: NSCoder) -> AVPlayerViewController? {let controller = AVPlayerViewController(coder: coder)controller?.player = queuePlayercontroller?.player?.play()return controller}
func caculateTime(seconds: Float64) -> String { //將總秒數變成 幾分幾秒並以文字呈現/*因Float64(Double)轉Int會出現NaN(Not A Number),故用guard else當條件 seconds是一個數字時 為不成立,回傳一個空字串,後續下面的就不執行了*/guard !(seconds.isNaN) else {print(seconds)print(seconds.isNaN)return ""}let time = Int(seconds)let min = Int(time / 60)let sec = Int(time % 60)var content = ""if min < 10 {content = "0\(min):"}else{content = "\(min):"}if sec < 10 {content += "0\(sec)"}else{content += "\(sec)"}return content}
func makePlayerItem(playItemUrl:String) { //變更光碟內容let url = Bundle.main.url(forResource: playItemUrl, withExtension: "mp4")!playerItem = AVPlayerItem(url: url)let duration = playerItem?.asset.duration //光碟的持續時間let totalSeconds = CMTimeGetSeconds(duration!) //變成秒數slider.minimumValue = 0slider.maximumValue = Float(totalSeconds)slider.isContinuous = true //想要拖動後才更新進度,那就設為 false;如果想要直接更新就設為 truemaxLabel.text = caculateTime(seconds: totalSeconds)}
func switchSong(arrayNumber:Int) {makePlayerItem(playItemUrl: playerItemUrl[arrayNumber])queuePlayer.replaceCurrentItem(with: playerItem)queuePlayer.play()ImageView.image = UIImage(named: songImage[number])playerLoop?.disableLooping() //關閉單曲循環}
func playOrPause(){if queuePlayer.timeControlStatus == .playing{playerButton[2].setTitle("▶️", for: UIControl.State.normal)queuePlayer.pause()}else{playerButton[2].setTitle("⏸", for: UIControl.State.normal)queuePlayer.play()}}
@IBAction func buttonTouchUp(_ sender: UIButton) {switch sender {case playerButton[0]: //隨機播放number = Int.random(in: 0...2)switchSong(arrayNumber: number)case playerButton[1]://上一首if number > 0 {number -= 1}else{number = 2}switchSong(arrayNumber: number)case playerButton[2]://播放或暫停playOrPause()case playerButton[3]://下一首if number < 2 {number += 1}else{number = 0}switchSong(arrayNumber: number)case playerButton[4]://單曲循環or全部輪播if sender.currentTitle == "🔁"{playerButton[4].setTitle("🔂", for: UIControl.State.normal)}else{playerButton[4].setTitle("🔁", for: UIControl.State.normal)}NotificationCenter.default.removeObserver(self.notification as Any) //先移除掉之前通知中心的觀察結果self.notification = NotificationCenter.default.addObserver(forName: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: nil, queue: .main) { [self] (Notification) in //通知中心默認加入一個觀察,觀察的事件為影片播畢時的動作switch sender.currentTitle {case "🔂": //單曲循環,重複播放queuePlayer.removeAllItems()switchSong(arrayNumber: number)playerLoop = AVPlayerLooper(player: queuePlayer, templateItem: playerItem!)case "🔁": //結束就換下一首,輪播playerLoop?.disableLooping()if number < 2 {number += 1}else{number = 0}queuePlayer.removeAllItems()switchSong(arrayNumber: number)default:break}}default:break}}
@IBAction func sliderChange(_ sender: UISlider) {queuePlayer.seek(to: CMTime(value: CMTimeValue(sender.value), timescale: 1))minLabel.text = caculateTime(seconds: Float64(sender.value))}
影片由自建的playerView呈現
@IBOutlet weak var playerView: UIView!
override func viewDidLoad() {super.viewDidLoad()
let playerController = AVPlayerViewController()playerController.player = queuePlayerplayerController.view.frame = CGRect(x: 0, y: 0, width: 350, height: 200)playerView.addSubview(playerController.view)self.addChild(playerController){