iOS-純程式碼編寫本地音樂播放器AVAudioPlayer
背景:天天聽著網易雲音樂,想著哪天要是自己能做一個類似網易雲音樂的播放器就好了(大三還沒畢業)。在CocoaChina程式碼庫裡面逛了有些日子了,就乾脆下載幾個音樂播放器的demo來練練手。實踐結果告訴我:一個完整的播放器確實要做很多功能,確實有些難度。那麼就開始說說我做的本地音樂播放器吧。
個人覺得吧,無論做什麼專案或工程,都要先架構好再寫,不然真的會很凌亂地。以前吧,我總是拿著東西就寫,從不管什麼架構,什麼分層的。如果逮著某個部分就寫,寫到最後你會發現,你的程式碼耦合性太強了,不容易分離。當另一個控制器或者View
層或者Model
層要用到當前資料,不容易傳遞。(傳遞當然是可以傳遞的,只是邏輯看起來很彆扭)。我個人還是比較喜歡先分好層,再寫程式碼。當然也有人喜歡全部寫好,再把每個部分分離出來,歸類為不同的層。我更喜歡前者。
好啦,開始說說我整個工程的架構吧:
- 採用
MVC
的模式來管理專案,層管理控制元件,View
層顯示控制元件,Model
層處理資料。 - 歌詞介面歸為View層(檢視內的要顯示東西太多,分離出來),其餘控制元件在主控制器初始化顯示。
- 自定義
UITableViewCell
來顯示歌詞,並且用演算法按照播放進度來顯示歌詞的顏色。 - 有一些演算法處理可以歸為
Category
分類或者自己建一個工具類。
再說說這個工程裡面的控制元件結構位置的概述吧:
第一個介面:
- 模糊的背景裡面是一個
UIImageView
,採用了高斯(毛玻璃)效果。中間那個圓圈圖片也是一個UIImageView
,並且修改他的Layer變成圓形。不難看出,這兩個UIImageView
- 上面歌名和歌手是用兩個
UILabel
來顯示,資訊也是從當前MP3歌曲裡面提取出來的。 - 下面有一個
UISlider
來控制歌曲播放進度。 - 還有兩個
UILabel
分別來顯示當前播放時間和歌曲總時長,歌曲裡面提取出來的總時長是時間戳NSTimeInterval
的單位,我們用演算法格式化轉發為我們熟知的時間格式。 最下面自然是三個
UIButton
,來控制歌曲的播放暫停、上一曲、下一曲。第二個介面:
顯示歌詞的部分,使用一個
UIScrollView
作為父檢視。真正顯示歌詞的部分是一個自定義cell
的UITableView
。這個UIScrollView
contentSize
有兩個螢幕寬度,UITableView
放在第二個螢幕寬度的位置,效果就是:向右滑動就到歌詞介面。- 繼承
UILabel
的ZFLabel
,並增加一個進度屬性,按照當前歌曲進度播放來繪製這個UILabel
的顏色(即播放到哪裡,歌詞顏色就顯示到哪裡)。把這個ZFLabel
作為自定義的cell
。 - 第一個介面其實還有一個當前歌詞的顯示,其實也就是讓他等於當前歌詞顯示的
ZFLabel
而已。
除此之外,本工程用了兩個計時器。第一個計時器為NSTimer
,用來更新第一個介面的播放時間。第二個計時器為CADisplayLink
,用來更新歌詞。為什麼要用兩個不一樣的計時器?第一個計時器NSTimer
我就不多說了,相信大家用得最多。第二個計時器不需要設定時間,每秒有固定的呼叫頻率,而且呼叫精確度相當高,比NSTimer
高。因為要顯示歌詞嘛,為了不出現卡頓的現象,就採用CADisplayLink
計時器。
至於播放器類,當然是用系統的類AVAudioPlayer
啦。一方面,我喜歡原生開發。另一方面,把系統的學會了,第三方的也是基於系統的嘛,學起來也很容易的。
對音訊最大的認識:
每個MP3裡面都已經錄製好了這首歌的資訊,比如:歌曲圖片(被我提取出來用來顯示高斯效果和中央旋轉圖)、歌手、歌曲名字、專輯名稱。
我們可以用AVURLAsset
和AVMetadataItem
提取出歌曲裡面的資訊。
程式碼:
#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
)的旋轉時間、旋轉角度之類的。
以上就是我這幾天寫該工程的心得~~~