作業#31 模仿 iOS 的 Music App 製作情歌點唱機

原本做完上一個作業想說繼續複習一下前面的漸層。。。結果Peter說 你還沒有做過 Music App 吧? Peter金口一開,只能先放下一切事物盡力做出來了!一開始的時候還蠻順利的,但是到了Slider 跟 音樂時間時就大卡關了。最後還是參考了學長姐的文章才順利做出來。。。

接下來跟大家分享我做好的Music App!

這是我拉的介面,等之後對TableView熟悉後 希望可以再加入一頁是TableView的音樂列表。

首先拉好元件的Outlet跟Action

這次的Action比較多,用綠色代表是有Outlet跟Action的;紅色就是只有Outlet。

宣告類別,常數、變數

宣告的變數跟常數,註解是各自的功用。

宣告的struct以及struct內容。

接下來就是比較複雜的Func

先從比較簡單的講起來

如何播放音樂以及更新畫面

這邊可以參考Peter的文章有詳細的講解,上面也有每個程式碼的註解跟功能。

//    播放音樂func playMusic(){//  宣告一個fileUrl來呼叫音樂的檔案let fileUrl = Bundle.main.url(forResource: allmusic[musicIndex].music , withExtension: "mp4")!//        儲存播放音樂的playerItemplayerItem = AVPlayerItem(url: fileUrl)//        播放音樂的playerplayer.replaceCurrentItem(with: playerItem)//        播放音樂player.play()}

更新畫面

這也是比較基礎的。跟以前做的大同小異!沒有什麼困難的!

//    更新歌曲、歌手、畫面圖片func updateUI(){musicNameLB.text = allmusic[musicIndex].musicNamesingerLB.text = allmusic[musicIndex].singermusicPicIV.image = UIImage(named: allmusic[musicIndex].musicPic)//        starTimeLB.text = String(player.currentTime().seconds)}

設定Symbols圖示大小以及圖片

我將它做成一個回傳是UIImage的Func可以設定你要的Symbols以及大小。

之後只要宣告.setImage就可以輕鬆的設定你想要的Symbols跟大小了。

//粗體的就是Func非常方便!
stopMusicButton.setImage(setbuttonImage(systemName: "pause.fill", pointSize: 30), for: .normal)
要執行才能看出差別!
//    設定Button圖示大小跟圖案func setbuttonImage(systemName:String,pointSize: Int)-> UIImage?{//        設定一個圖示以及他的長寬let sfsymbol = UIImage.SymbolConfiguration(pointSize: CGFloat(pointSize), weight: .bold,scale: .large)//        設定圖片名字,跟他的出處let sfsymbolImage = UIImage(systemName: systemName, withConfiguration: sfsymbol)//        回傳return sfsymbolImage}

上\下一首歌的Func

這邊也是比較簡單的部分!只要讓musicIndex +1就可以跳到下一首。也要先確認shuffleIndex是否有開啟有的話就要用Int.random(in: 0…allmusic.count — 1)亂數曲歌。

//    播放下一首歌func playNextSound(){//        如果隨機播放是打開的if shuffleIndex == 1{//            就用亂數播歌musicIndex = Int.random(in: 0...allmusic.count - 1)updateUI()playMusic()updateMusciUI()}else{//            如果不是就是照列表播歌musicIndex += 1if musicIndex < allmusic.count{updateUI()playMusic()updateMusciUI()}else{musicIndex = 0updateUI()playMusic()updateMusciUI()}}}

確認Slider的最大秒數 最大秒數轉成分鐘+秒數的Func

接下來就是比較困難的地方了。。。我也是參考了許多學長姐的文章最終才完成的!雖然有些真的還是不太清楚。但是至少那個程式碼的功用!

讓Slider跟著音樂跑的Func

要讓Slider按照著秒數跑真的是不簡單,我大概看了半天的我還是不太理解他的運作。我覺得是這次作業最困難的地方!再好好研究研究。。。

//    播放幾秒的Funcfunc nowPlayTime(){//        播放的計數器從1開始每一秒都在播放player.addPeriodicTimeObserver(forInterval: CMTimeMake(value: 1, timescale: 1), queue: DispatchQueue.main, using: { (CMTime) in//          如果音樂要播放if self.player.currentItem?.status == .readyToPlay{//                就會得到player播放的時間let currenTime = CMTimeGetSeconds(self.player.currentTime())//                Slider移動就會等於currenTime的時間self.playTimeSlider.value = Float(currenTime)//                顯示播放了幾秒self.starTimeLB.text = self.timeShow(time: currenTime)}})}

確認音樂結束後下一首從頭播放

這邊也是偏困難的地方,那時候做好前面後看到slider開始跟著動很開心。但是發現一首歌結束後除非自己按下一首不然他不會自動換歌。最後又研究了許久。才知道要加入這個Func。

/    確認音樂結束func musicEnd(){//        叫出  NotificationCenter.default.addObserver來確認音樂是否結束NotificationCenter.default.addObserver(forName: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: nil, queue: .main) { (_) in//            如果結束有打開repeatBool 就會從頭播放if self.repeatBool{let musicEndTime: CMTime = CMTimeMake(value: 0, timescale: 1)self.player.seek(to: musicEndTime)self.player.play()}else{//            如果結束沒有打開repeatBool就會撥下一首歌self.playNextSound()}}}

將Func套入到@IBAction裡

暫停、播放、下一首、Slider調音樂到幾秒

這邊是比較簡單的部分。只是下面的Slider也是有點困難的地方。

可以看到我也是用比較簡單易懂得寫法使用index等於1或0來控制圖案。

重複播放\隨機播放

這邊也比較簡單,因為都寫在Func裡,這邊只要設定按下去後變更的圖示就好。

看到Slider會動的時候真的很開心!

最後是加入MV

我這邊是使用 AVPlayerViewController來播放MV好處是,不用設定什麼!帥哥學長教我用override func prepare(for segue: UIStoryboardSegue, sender: Any?)來播放!我覺得非常方便!

//    播放當前在播放的東西override func prepare(for segue: UIStoryboardSegue, sender: Any?) {//        讓影片播放跟主頁一樣let MyAVPlayerVC = segue.destination as! MyAVPlayerViewController//        播放MyAVPlayerVC.player = player}

成品展示

參考作品:

--

--