今天給同學(xué)們帶來(lái)音頻,音樂(lè)蔗牡,和視頻播放相關(guān)的案例那么廢話不多說(shuō)直接上代碼!先看演示示例:
iOS開(kāi)發(fā)-音樂(lè)播放器(簡(jiǎn)單版).gif
//
// ZZMusic.h
// 05-音樂(lè)播放器
//
// Created by 周昭 on 2017/3/20.
// Copyright ? 2017年 ZZ. All rights reserved.
//
#warning - 對(duì)模型的處理借助MJExtension
#import <Foundation/Foundation.h>
@interface ZZMusic : NSObject
@property (copy, nonatomic) NSString *name;
@property (copy, nonatomic) NSString *filename;
@property (copy, nonatomic) NSString *singer;
@property (copy, nonatomic) NSString *singerIcon;
@property (copy, nonatomic) NSString *icon;
@property (nonatomic, assign, getter = isPlaying) BOOL playing;
@end
//
// ZZMusic.m
// 05-音樂(lè)播放器
//
// Created by 周昭 on 2017/3/20.
// Copyright ? 2017年 ZZ. All rights reserved.
//
#import "ZZMusic.h"
@implementation ZZMusic
@end
//
// ZZMusicCell.h
// 05-音樂(lè)播放器
//
// Created by 周昭 on 2017/3/20.
// Copyright ? 2017年 ZZ. All rights reserved.
//
#import <UIKit/UIKit.h>
@class ZZMusic;
@interface ZZMusicCell : UITableViewCell
+ (instancetype)cellWithTableView:(UITableView *)tableView;
@property (nonatomic, strong) ZZMusic *music;
@end
//
// ZZMusicCell.m
// 05-音樂(lè)播放器
//
// Created by 周昭 on 2017/3/20.
// Copyright ? 2017年 ZZ. All rights reserved.
//
#import "ZZMusicCell.h"
#import "ZZMusic.h"
#import "Colours.h"
#import "UIImage+ZZ.h"
@interface ZZMusicCell()
/**
* 定時(shí)器
*/
@property (nonatomic, strong) CADisplayLink *link;
@end
@implementation ZZMusicCell
- (CADisplayLink *)link
{
if (!_link) {
self.link = [CADisplayLink displayLinkWithTarget:self selector:@selector(update)];
}
return _link;
}
+ (instancetype)cellWithTableView:(UITableView *)tableView
{
static NSString *ID = @"music";
ZZMusicCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
if (cell == nil) {
cell = [[ZZMusicCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:ID];
}
return cell;
}
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
self.backgroundColor = [UIColor clearColor];
self.selectedBackgroundView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"backgroundImage"]];
}
return self;
}
- (void)setMusic:(ZZMusic *)music
{
_music = music;
self.textLabel.text = music.name;
self.detailTextLabel.text = music.singer;
self.imageView.image = [UIImage circleImageWithName:music.singerIcon borderWidth:2 borderColor:[UIColor skyBlueColor]];
if (music.isPlaying) {
[self.link addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
} else { // 停止動(dòng)畫(huà)
[self.link invalidate];
self.link = nil;
self.imageView.transform = CGAffineTransformIdentity;
}
}
/**
* 8秒轉(zhuǎn)一圈, 45°/s
*/
- (void)update
{
// 1/60秒 * 45
// 規(guī)定時(shí)間內(nèi)轉(zhuǎn)動(dòng)的角度 == 時(shí)間 * 速度
CGFloat angle = self.link.duration * M_PI_4;
self.imageView.transform = CGAffineTransformRotate(self.imageView.transform, angle);
}
- (void)dealloc
{
// 移除定時(shí)器
[self.link removeFromRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
}
@end
//
// UIImage+ZZ.h
// 05-音樂(lè)播放器
//
// Created by 周昭 on 2017/3/20.
// Copyright ? 2017年 ZZ. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface UIImage (ZZ)
+ (instancetype)circleImageWithName:(NSString *)name borderWidth:(CGFloat)borderWidth borderColor:(UIColor *)borderColor;
@end
//
// UIImage+ZZ.m
// 05-音樂(lè)播放器
//
// Created by 周昭 on 2017/3/20.
// Copyright ? 2017年 ZZ. All rights reserved.
//
#import "UIImage+ZZ.h"
@implementation UIImage (ZZ)
+ (instancetype)circleImageWithName:(NSString *)name borderWidth:(CGFloat)borderWidth borderColor:(UIColor *)borderColor
{
// 1.加載原圖
UIImage *oldImage = [UIImage imageNamed:name];
// 2.開(kāi)啟上下文
CGFloat imageW = oldImage.size.width + 2 * borderWidth;
CGFloat imageH = oldImage.size.height + 2 * borderWidth;
CGSize imageSize = CGSizeMake(imageW, imageH);
UIGraphicsBeginImageContextWithOptions(imageSize, NO, 0.0);
// 3.取得當(dāng)前的上下文
CGContextRef ctx = UIGraphicsGetCurrentContext();
// 4.畫(huà)邊框(大圓)
[borderColor set];
CGFloat bigRadius = imageW * 0.5; // 大圓半徑
CGFloat centerX = bigRadius; // 圓心
CGFloat centerY = bigRadius;
CGContextAddArc(ctx, centerX, centerY, bigRadius, 0, M_PI * 2, 0);
CGContextFillPath(ctx); // 畫(huà)圓
// 5.小圓
CGFloat smallRadius = bigRadius - borderWidth;
CGContextAddArc(ctx, centerX, centerY, smallRadius, 0, M_PI * 2, 0);
// 裁剪(后面畫(huà)的東西才會(huì)受裁剪的影響)
CGContextClip(ctx);
// 6.畫(huà)圖
[oldImage drawInRect:CGRectMake(borderWidth, borderWidth, oldImage.size.width, oldImage.size.height)];
// 7.取圖
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
// 8.結(jié)束上下文
UIGraphicsEndImageContext();
return newImage;
}
@end
//
// ZZAudioTool.h
// 05-音樂(lè)播放器
//
// Created by 周昭 on 2017/3/20.
// Copyright ? 2017年 ZZ. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <AVFoundation/AVFoundation.h>
@interface ZZAudioTool : NSObject
/**
* 播放器
*/
@property(nonatomic, strong) AVAudioPlayer *player;
/**
* 創(chuàng)建單例
*/
+ (instancetype)shareInstance;
/**
* 播放音效
*
* @param filename 音效文件名
*/
+ (void)playSound:(NSString *)filename;
/**
* 銷毀音效
*
* @param filename 音效文件名
*/
+ (void)disposeSound:(NSString *)filename;
/**
* 播放音樂(lè)
*
* @param filename 音樂(lè)文件名
*/
+ (AVAudioPlayer *)playMusic:(NSString *)filename;
/**
* 暫停音樂(lè)
*
* @param filename 音樂(lè)文件名
*/
+ (void)pauseMusic:(NSString *)filename;
/**
* 停止音樂(lè)
*
* @param filename 音樂(lè)文件名
*/
+ (void)stopMusic:(NSString *)filename;
/**
* 返回當(dāng)前正在播放的音樂(lè)播放器
*/
+ (AVAudioPlayer *)currentPlayingAudioPlayer;
@end
//
// ZZAudioTool.m
// 05-音樂(lè)播放器
//
// Created by 周昭 on 2017/3/20.
// Copyright ? 2017年 ZZ. All rights reserved.
//
#import "ZZAudioTool.h"
@implementation ZZAudioTool
/**
* 存放所有的音頻ID
* 字典: filename作為key, soundID作為value
*/
static NSMutableDictionary *_soundIDDict;
/**
* 存放所有的音樂(lè)播放器
* 字典: filename作為key, audioPlayer作為value
*/
static NSMutableDictionary *_audioPlayerDict;
/**
* 返回請(qǐng)求單例對(duì)象
*/
+ (instancetype)shareInstance
{
static ZZAudioTool *audioTool;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
if (audioTool == nil) {
audioTool = [[ZZAudioTool alloc] init];
}
});
return audioTool;
}
/**
* 初始化
*/
+ (void)initialize
{
_soundIDDict = [NSMutableDictionary dictionary];
_audioPlayerDict = [NSMutableDictionary dictionary];
// 設(shè)置音頻會(huì)話類型
AVAudioSession *session = [AVAudioSession sharedInstance];
[session setCategory:AVAudioSessionCategorySoloAmbient error:nil];
[session setActive:YES error:nil];
}
/**
* 播放音效
*
* @param filename 音效文件名
*/
+ (void)playSound:(NSString *)filename
{
if (!filename) return;
// 1.從字典中取出soundID
SystemSoundID soundID = [_soundIDDict[filename] unsignedLongValue];
if (!soundID) { // 創(chuàng)建
// 加載音效文件
NSURL *url = [[NSBundle mainBundle] URLForResource:filename withExtension:nil];
if (!url) return;
// 創(chuàng)建音效ID
AudioServicesCreateSystemSoundID((__bridge CFURLRef)url, &soundID);
// 放入字典
_soundIDDict[filename] = @(soundID);
}
// 2.播放
AudioServicesPlaySystemSound(soundID);
}
/**
* 銷毀音效
*
* @param filename 音效文件名
*/
+ (void)disposeSound:(NSString *)filename
{
if (!filename) return;
SystemSoundID soundID = [_soundIDDict[filename] unsignedLongValue];
if (soundID) {
// 銷毀音效ID
AudioServicesDisposeSystemSoundID(soundID);
// 從字典中移除
[_soundIDDict removeObjectForKey:filename];
}
}
/**
* 播放音樂(lè)
*
* @param filename 音樂(lè)文件名
*/
+ (AVAudioPlayer *)playMusic:(NSString *)filename
{
if (!filename) return nil;
// 1.從字典中取出audioPlayer
AVAudioPlayer *audioPlayer = _audioPlayerDict[filename];
if (!audioPlayer) { // 創(chuàng)建
// 加載音樂(lè)文件
NSURL *url = [[NSBundle mainBundle] URLForResource:filename withExtension:nil];
if (!url) return nil;
// 創(chuàng)建audioPlayer
audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil];
// 緩沖
[audioPlayer prepareToPlay];
// audioPlayer.enableRate = YES;
// audioPlayer.rate = 10.0;
// 放入字典
_audioPlayerDict[filename] = audioPlayer;
}
// 2.播放
if (!audioPlayer.isPlaying) {
[audioPlayer play];
}
return audioPlayer;
}
/**
* 暫停音樂(lè)
*
* @param filename 音樂(lè)文件名
*/
+ (void)pauseMusic:(NSString *)filename
{
if (!filename) return;
// 1.從字典中取出audioPlayer
AVAudioPlayer *audioPlayer = _audioPlayerDict[filename];
// 2.暫停
if (audioPlayer.isPlaying) {
[audioPlayer pause];
}
}
/**
* 停止音樂(lè)
*
* @param filename 音樂(lè)文件名
*/
+ (void)stopMusic:(NSString *)filename
{
if (!filename) return;
// 1.從字典中取出audioPlayer
AVAudioPlayer *audioPlayer = _audioPlayerDict[filename];
// 2.暫停
if (audioPlayer.isPlaying) {
[audioPlayer stop];
// 直接銷毀
[_audioPlayerDict removeObjectForKey:filename];
}
}
/**
* 返回當(dāng)前正在播放的音樂(lè)播放器
*/
+ (AVAudioPlayer *)currentPlayingAudioPlayer
{
for (NSString *filename in _audioPlayerDict) {
AVAudioPlayer *audioPlayer = _audioPlayerDict[filename];
if (audioPlayer.isPlaying) {
return audioPlayer;
}
}
return nil;
}
@end
//
// ZZMusicsController.h
// 05-音樂(lè)播放器
//
// Created by 周昭 on 2017/3/20.
// Copyright ? 2017年 ZZ. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface ZZMusicsController : UIViewController
@end
//
// ZZMusicsController.m
// 05-音樂(lè)播放器
//
// Created by 周昭 on 2017/3/20.
// Copyright ? 2017年 ZZ. All rights reserved.
//
#import "ZZMusicsController.h"
#import "ZZMusic.h"
#import "ZZMusicCell.h"
#import "ZZAudioTool.h"
#import "MJExtension.h"
#import "NSString+ZZ.h"
#import <AVFoundation/AVFoundation.h>
#import <MediaPlayer/MediaPlayer.h>
@interface ZZMusicsController ()<UITableViewDelegate,UITableViewDataSource,AVAudioPlayerDelegate>
@property (nonatomic, strong) NSArray *musics;
@property (nonatomic, strong) AVAudioPlayer *currentPlayingAudioPlayer;
@property (nonatomic, weak) UITableView *tableView;
@property (nonatomic, weak) UIImageView *imgView;
@end
@implementation ZZMusicsController
#pragma mark - 懶加載
- (NSArray *)musics
{
if (!_musics) {
self.musics = [ZZMusic objectArrayWithFilename:@"Musics.plist"];
}
return _musics;
}
- (void)viewDidLoad {
[super viewDidLoad];
// 0.設(shè)置標(biāo)題&背景
[self setUpTitle];
// 1.初始化tableView
[self setUpTableView];
}
#pragma mark - setUp 初始化
- (void)setUpTableView
{
// 0.創(chuàng)建tableView
UITableView *tableView = [[UITableView alloc] init];
tableView.delegate = self;
tableView.dataSource = self;
tableView.tableFooterView = [[UIView alloc] init];
// 1.設(shè)置背景
UIImageView *imgView = [[UIImageView alloc] init];
imgView.frame = self.view.frame;
imgView.image = [UIImage imageNamed:@"backgroundImage"];
tableView.backgroundView = imgView;
tableView.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height);
[self.view addSubview:tableView];
self.tableView = tableView;
}
- (void)setUpTitle
{
// 0.設(shè)置標(biāo)題
self.title = NSLocalizedString(@"音樂(lè)播放器", nil);
}
#pragma mark - Table view data source
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.musics.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// 1.創(chuàng)建cell
ZZMusicCell *cell = [ZZMusicCell cellWithTableView:tableView];
// 2.設(shè)置cell的數(shù)據(jù)
cell.music = self.musics[indexPath.row];
return cell;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 70;
}
- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath
{
// 停止音樂(lè)
ZZMusic *music = self.musics[indexPath.row];
[ZZAudioTool stopMusic:music.filename];
// 再次傳遞模型
ZZMusicCell *cell = (ZZMusicCell *)[tableView cellForRowAtIndexPath:indexPath];
music.playing = NO;
cell.music = music;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// 取出當(dāng)前點(diǎn)擊的cell
ZZMusicCell *cell = (ZZMusicCell *)[tableView cellForRowAtIndexPath:indexPath];
// 取出要播放的音樂(lè)
ZZMusic *music = self.musics[indexPath.row];
if (music.playing) {
[ZZAudioTool pauseMusic:music.filename];
music.playing = NO;
cell.music = music;
} else {
AVAudioPlayer *audioPlayer = [ZZAudioTool playMusic:music.filename];
audioPlayer.delegate = self;
self.currentPlayingAudioPlayer = audioPlayer;
// 在鎖屏界面顯示歌曲信息
[self showInfoInLockedScreen:music];
// 再次傳遞模型
music.playing = YES;
cell.music = music;
}
}
/**
* 在鎖屏界面顯示歌曲信息
*/
- (void)showInfoInLockedScreen:(ZZMusic *)music
{
NSMutableDictionary *info = [NSMutableDictionary dictionary];
// 標(biāo)題(音樂(lè)名稱)
info[MPMediaItemPropertyTitle] = music.name;
// 作者
info[MPMediaItemPropertyArtist] = music.singer;
// 專輯
info[MPMediaItemPropertyAlbumTitle] = music.singer;
// 圖片
info[MPMediaItemPropertyArtwork] = [[MPMediaItemArtwork alloc] initWithImage:[UIImage imageNamed:music.icon]];
[MPNowPlayingInfoCenter defaultCenter].nowPlayingInfo = info;
}
#pragma mark - AVAudioPlayerDelegate
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag
{
// 計(jì)算下一行
NSIndexPath *selectedPath = [self.tableView indexPathForSelectedRow];
NSInteger nextRow = selectedPath.row + 1;
if (nextRow == self.musics.count) {
nextRow = 0;
}
#warning 停止上一首歌的轉(zhuǎn)圈
// 再次傳遞模型
ZZMusicCell *cell = (ZZMusicCell *)[self.tableView cellForRowAtIndexPath:selectedPath];
ZZMusic *music = self.musics[selectedPath.row];
music.playing = NO;
cell.music = music;
// 播放下一首歌
NSIndexPath *currentPath = [NSIndexPath indexPathForRow:nextRow inSection:selectedPath.section];
[self.tableView selectRowAtIndexPath:currentPath animated:YES scrollPosition:UITableViewScrollPositionTop];
[self tableView:self.tableView didSelectRowAtIndexPath:currentPath];
}
/**
* 音樂(lè)播放器被打斷(打\接電話)
*/
- (void)audioPlayerBeginInterruption:(AVAudioPlayer *)player
{
NSLog(@"audioPlayerBeginInterruption---被打斷");
}
/**
* 音樂(lè)播放器停止打斷(打\接電話)
*/
- (void)audioPlayerEndInterruption:(AVAudioPlayer *)player withOptions:(NSUInteger)flags
{
NSLog(@"audioPlayerEndInterruption---停止打斷");
[player play];
}
@end