1. 程式人生 > >iOS-純程式碼編寫本地音樂播放器AVAudioPlayer

iOS-純程式碼編寫本地音樂播放器AVAudioPlayer

背景:天天聽著網易雲音樂,想著哪天要是自己能做一個類似網易雲音樂的播放器就好了(大三還沒畢業)。在CocoaChina程式碼庫裡面逛了有些日子了,就乾脆下載幾個音樂播放器的demo來練練手。實踐結果告訴我:一個完整的播放器確實要做很多功能,確實有些難度。那麼就開始說說我做的本地音樂播放器吧。

個人覺得吧,無論做什麼專案或工程,都要先架構好再寫,不然真的會很凌亂地。以前吧,我總是拿著東西就寫,從不管什麼架構,什麼分層的。如果逮著某個部分就寫,寫到最後你會發現,你的程式碼耦合性太強了,不容易分離。當另一個控制器或者View層或者Model層要用到當前資料,不容易傳遞。(傳遞當然是可以傳遞的,只是邏輯看起來很彆扭)。我個人還是比較喜歡先分好層,再寫程式碼。當然也有人喜歡全部寫好,再把每個部分分離出來,歸類為不同的層。我更喜歡前者。

好啦,開始說說我整個工程的架構吧:

  • 採用MVC的模式來管理專案,層管理控制元件,View層顯示控制元件,Model層處理資料。
  • 歌詞介面歸為View層(檢視內的要顯示東西太多,分離出來),其餘控制元件在主控制器初始化顯示。
  • 自定義UITableViewCell來顯示歌詞,並且用演算法按照播放進度來顯示歌詞的顏色。
  • 有一些演算法處理可以歸為Category分類或者自己建一個工具類。

再說說這個工程裡面的控制元件結構位置的概述吧:

第一個介面:

  • 模糊的背景裡面是一個UIImageView,採用了高斯(毛玻璃)效果。中間那個圓圈圖片也是一個UIImageView,並且修改他的Layer變成圓形。不難看出,這兩個UIImageView
    的圖片是一樣的,其實是從當前MP3音樂裡面提取出來的。
  • 上面歌名和歌手是用兩個UILabel來顯示,資訊也是從當前MP3歌曲裡面提取出來的。
  • 下面有一個UISlider來控制歌曲播放進度。
  • 還有兩個UILabel分別來顯示當前播放時間和歌曲總時長,歌曲裡面提取出來的總時長是時間戳NSTimeInterval的單位,我們用演算法格式化轉發為我們熟知的時間格式。
  • 最下面自然是三個UIButton,來控制歌曲的播放暫停、上一曲、下一曲。

    第二個介面:

  • 顯示歌詞的部分,使用一個UIScrollView作為父檢視。真正顯示歌詞的部分是一個自定義cellUITableView。這個UIScrollView

    contentSize有兩個螢幕寬度,UITableView放在第二個螢幕寬度的位置,效果就是:向右滑動就到歌詞介面。

  • 繼承UILabelZFLabel,並增加一個進度屬性,按照當前歌曲進度播放來繪製這個UILabel的顏色(即播放到哪裡,歌詞顏色就顯示到哪裡)。把這個ZFLabel作為自定義的cell
  • 第一個介面其實還有一個當前歌詞的顯示,其實也就是讓他等於當前歌詞顯示的ZFLabel而已。

除此之外,本工程用了兩個計時器。第一個計時器為NSTimer,用來更新第一個介面的播放時間。第二個計時器為CADisplayLink,用來更新歌詞。為什麼要用兩個不一樣的計時器?第一個計時器NSTimer我就不多說了,相信大家用得最多。第二個計時器不需要設定時間,每秒有固定的呼叫頻率,而且呼叫精確度相當高,比NSTimer高。因為要顯示歌詞嘛,為了不出現卡頓的現象,就採用CADisplayLink計時器。

至於播放器類,當然是用系統的類AVAudioPlayer啦。一方面,我喜歡原生開發。另一方面,把系統的學會了,第三方的也是基於系統的嘛,學起來也很容易的。

這裡寫圖片描述

這裡寫圖片描述

對音訊最大的認識:

每個MP3裡面都已經錄製好了這首歌的資訊,比如:歌曲圖片(被我提取出來用來顯示高斯效果和中央旋轉圖)、歌手、歌曲名字、專輯名稱。

我們可以用AVURLAssetAVMetadataItem提取出歌曲裡面的資訊。

程式碼:

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>

@interface AssetModel : NSObject

/**圖片*/
@property(nonatomic,strong) UIImage *image;
/**歌曲名*/
@property(nonatomic,strong) NSString *songName;
/**歌手*/
@property(nonatomic,strong) NSString *artist;
/**專輯名稱*/
@property(nonatomic,strong) NSString *albumName;


/**
 初始化歌曲的資訊,包括歌曲的圖片、歌曲名、歌手、專輯名稱資訊

 @param url 歌曲的url路徑
 @return 初始化好的物件
 */
+(AssetModel *)AssetModelWithURL:(NSURL *)url;
-(AssetModel *)initAssetWithURL:(NSURL *)url;

@end
#import "AssetModel.h"

@implementation AssetModel

+(AssetModel *)AssetModelWithURL:(NSURL *)url
{
    return [[self alloc] initAssetWithURL:url];
}


-(AssetModel *)initAssetWithURL:(NSURL *)url
{
        AVURLAsset *mp3Asset = [AVURLAsset URLAssetWithURL:url options:nil];

        for (NSString *format in [mp3Asset availableMetadataFormats]) {
            for (AVMetadataItem *metadataItem in [mp3Asset metadataForFormat:format]) {
                if ([metadataItem.commonKey isEqual:@"artwork"]) {
                    //提取圖片
                    self.image = [UIImage imageWithData:(NSData *)metadataItem.value];
                }
                else if ([metadataItem.commonKey isEqualToString:@"title"])
                {
                    //提取歌曲名
                    self.songName = (NSString *)metadataItem.value;
                }
                else if ([metadataItem.commonKey isEqualToString:@"artist"])
                {
                    //提取歌手
                    self.artist = (NSString *)metadataItem.value;
                }
                else if ([metadataItem.commonKey isEqualToString:@"albumName"])
                {
                    //提取專輯名稱
                    self.albumName = (NSString *)metadataItem.value;
                }
            }
        }
    return self;
}

@end

對動畫的最大認識:

CoreAnimation裡面有四種:基礎動畫、幀動畫、轉場動畫、組動畫。而該工程只是用到了基礎動畫CABasicAnimation。點選播放音樂時候,就讓中央旋轉圖開始沿著Z軸方向旋轉。當然,要設定中央旋轉圖(UIImageView)的旋轉時間、旋轉角度之類的。

以上就是我這幾天寫該工程的心得~~~