您的位置:首页 > 移动开发 > IOS开发

iOS开发拓展篇—音频处理(音乐播放器3)

2015-06-30 16:10 471 查看
iOS开发拓展篇—音频处理(音乐播放器3)
说明:这篇文章主要介绍音频工具类和播放工具类的封装。
一、控制器间数据传递
1.两个控制器之间数据的传递
第一种方法:self.parentViewController.music=self.music[indexPath.row];不能满足
第二种做法:把整个数组传递给它
第三种做法:设置一个数据源,设置播放控制器的数据源是这个控制器。self.parentViewController.dataSource=self;好处:没有耦合性,任何实现了协议的可以作为数据源。
第四种做法:把整个项目会使用到的音频资源交给一个工具类去管理,这样就不用传递过去了。直接向工具类索要资源就可以。

二、封装一个音频工具类
新建一个音频工具类,用来管理音乐数据(音乐模型)
  


工具类中的代码设计如下:
YYMusicTool.h文件

1 //
2 //  YYMusicTool.h
3 //
4
5 #import <Foundation/Foundation.h>
6 @class YYMusicModel;
7 @interface YYMusicTool : NSObject
8 /**
9  *  返回所有的歌曲
10  */
11 + (NSArray *)musics;
12
13 /**
14  *  返回正在播放的歌曲
15  */
16 + (YYMusicModel *)playingMusic;
17 + (void)setPlayingMusic:(YYMusicModel *)playingMusic;
18
19 /**
20  *  下一首歌曲
21  */
22 + (YYMusicModel *)nextMusic;
23
24 /**
25  *  上一首歌曲
26  */
27 + (YYMusicModel *)previousMusic;
28 @end


YYMusicTool.m文件

1 //
2 //  YYMusicTool.m
3 //
4
5 #import "YYMusicTool.h"
6 #import "YYMusicModel.h"
7 #import "MJExtension.h"
8
9 @implementation YYMusicTool
10
11 static NSArray *_musics;
12 static  YYMusicModel *_playingMusic;
13
14 /**
15  *  @return 返回所有的歌曲
16  */
17 +(NSArray *)musics
18 {
19     if (_musics==nil) {
20         _musics=[YYMusicModel objectArrayWithFilename:@"Musics.plist"];
21     }
22     return _musics;
23 }
24
25 +(void)setPlayingMusic:(YYMusicModel *)playingMusic
26 {
27     /*
28      *如果没有传入需要播放的歌曲,或者是传入的歌曲名不在音乐库中,那么就直接返回
29       如果需要播放的歌曲就是当前正在播放的歌曲,那么直接返回
30      */
31     if (!playingMusic || ![[self musics]containsObject:playingMusic]) return;
32     if (_playingMusic == playingMusic) return;
33     _playingMusic=playingMusic;
34 }
35 /**
36  *  返回正在播放的歌曲
37  */
38 +(YYMusicModel *)playingMusic
39 {
40     return _playingMusic;
41 }
42
43 /**
44  *  下一首歌曲
45  */
46 +(YYMusicModel *)nextMusic
47 {
48     //设定一个初值
49     int nextIndex = 0;
50     if (_playingMusic) {
51         //获取当前播放音乐的索引
52         int playingIndex = [[self musics] indexOfObject:_playingMusic];
53         //设置下一首音乐的索引
54         nextIndex = playingIndex+1;
55         //检查数组越界,如果下一首音乐是最后一首,那么重置为0
56         if (nextIndex>=[self musics].count) {
57             nextIndex=0;
58         }
59     }
60     return [self musics][nextIndex];
61 }
62
63 /**
64  *  上一首歌曲
65  */
66 +(YYMusicModel *)previousMusic
67 {
68     //设定一个初值
69     int previousIndex = 0;
70     if (_playingMusic) {
71         //获取当前播放音乐的索引
72         int playingIndex = [[self musics] indexOfObject:_playingMusic];
73         //设置下一首音乐的索引
74         previousIndex = playingIndex-1;
75         //检查数组越界,如果下一首音乐是最后一首,那么重置为0
76         if (previousIndex<0) {
77             previousIndex=[self musics].count-1;
78         }
79     }
80     return [self musics][previousIndex];
81 }
82 @end


三、封装一个音乐播放工具类
该工具类中的代码设计如下:
YYAudioTool.h文件

1 //
2 //  YYAudioTool.h
3 //
4
5 #import <Foundation/Foundation.h>
6 #import <AVFoundation/AVFoundation.h>
7 @interface YYAudioTool : NSObject
8 /**
9  *播放音乐文件
10  */
11 +(BOOL)playMusic:(NSString *)filename;
12 /**
13  *暂停播放
14  */
15 +(void)pauseMusic:(NSString *)filename;
16 /**
17  *播放音乐文件
18  */
19 +(void)stopMusic:(NSString *)filename;
20
21 /**
22  *播放音效文件
23  */
24 +(void)playSound:(NSString *)filename;
25 /**
26  *销毁音效
27  */
28 +(void)disposeSound:(NSString *)filename;
29 @end


YYAudioTool.m文件

1 //
2 //  YYAudioTool.m
3 //
4
5 #import "YYAudioTool.h"
6
7 @implementation YYAudioTool
8 /**
9  *存放所有的音乐播放器
10  */
11 static NSMutableDictionary *_musicPlayers;
12 +(NSMutableDictionary *)musicPlayers
13 {
14     if (_musicPlayers==nil) {
15         _musicPlayers=[NSMutableDictionary dictionary];
16     }
17     return _musicPlayers;
18 }
19
20 /**
21  *存放所有的音效ID
22  */
23 static NSMutableDictionary *_soundIDs;
24 +(NSMutableDictionary *)soundIDs
25 {
26     if (_soundIDs==nil) {
27         _soundIDs=[NSMutableDictionary dictionary];
28     }
29     return _soundIDs;
30 }
31
32
33 /**
34  *播放音乐
35  */
36 +(BOOL)playMusic:(NSString *)filename
37 {
38     if (!filename) return NO;//如果没有传入文件名,那么直接返回
39     //1.取出对应的播放器
40     AVAudioPlayer *player=[self musicPlayers][filename];
41
42     //2.如果播放器没有创建,那么就进行初始化
43     if (!player) {
44         //2.1音频文件的URL
45         NSURL *url=[[NSBundle mainBundle]URLForResource:filename withExtension:nil];
46         if (!url) return NO;//如果url为空,那么直接返回
47
48         //2.2创建播放器
49         player=[[AVAudioPlayer alloc]initWithContentsOfURL:url error:nil];
50
51         //2.3缓冲
52         if (![player prepareToPlay]) return NO;//如果缓冲失败,那么就直接返回
53
54         //2.4存入字典
55         [self musicPlayers][filename]=player;
56     }
57
58     //3.播放
59     if (![player isPlaying]) {
60         //如果当前没处于播放状态,那么就播放
61         return [player play];
62     }
63
64     return YES;//正在播放,那么就返回YES
65 }
66
67 +(void)pauseMusic:(NSString *)filename
68 {
69     if (!filename) return;//如果没有传入文件名,那么就直接返回
70
71     //1.取出对应的播放器
72     AVAudioPlayer *player=[self musicPlayers][filename];
73
74     //2.暂停
75     [player pause];//如果palyer为空,那相当于[nil pause],因此这里可以不用做处理
76
77 }
78
79 +(void)stopMusic:(NSString *)filename
80 {
81     if (!filename) return;//如果没有传入文件名,那么就直接返回
82
83     //1.取出对应的播放器
84     AVAudioPlayer *player=[self musicPlayers][filename];
85
86     //2.停止
87     [player stop];
88
89     //3.将播放器从字典中移除
90     [[self musicPlayers] removeObjectForKey:filename];
91 }
92
93 //播放音效
94 +(void)playSound:(NSString *)filename
95 {
96     if (!filename) return;
97     //1.取出对应的音效
98     SystemSoundID soundID=[[self soundIDs][filename] unsignedIntegerValue];
99
100     //2.播放音效
101     //2.1如果音效ID不存在,那么就创建
102     if (!soundID) {
103
104         //音效文件的URL
105         NSURL *url=[[NSBundle mainBundle]URLForResource:filename withExtension:nil];
106         if (!url) return;//如果URL不存在,那么就直接返回
107
108         OSStatus status = AudioServicesCreateSystemSoundID((__bridge CFURLRef)(url), &soundID);
109         NSLog(@"%ld",status);
110         //存入到字典中
111         [self soundIDs][filename]=@(soundID);
112     }
113
114     //2.2有音效ID后,播放音效
115     AudioServicesPlaySystemSound(soundID);
116 }
117
118 //销毁音效
119 +(void)disposeSound:(NSString *)filename
120 {
121     //如果传入的文件名为空,那么就直接返回
122     if (!filename) return;
123
124     //1.取出对应的音效
125     SystemSoundID soundID=[[self soundIDs][filename] unsignedIntegerValue];
126
127     //2.销毁
128     if (soundID) {
129         AudioServicesDisposeSystemSoundID(soundID);
130
131         //2.1销毁后,从字典中移除
132         [[self soundIDs]removeObjectForKey:filename];
133     }
134 }
135 @end


四、在音乐播放控制器中的代码处理
YYPlayingViewController.m文件

1 //
2 //  YYPlayingViewController.m
3 //
4
5 #import "YYPlayingViewController.h"
6 #import "YYMusicTool.h"
7 #import "YYMusicModel.h"
8 #import "YYAudioTool.h"
9
10 @interface YYPlayingViewController ()
11 @property (weak, nonatomic) IBOutlet UIImageView *iconView;
12 @property (weak, nonatomic) IBOutlet UILabel *songLabel;
13 @property (weak, nonatomic) IBOutlet UILabel *singerLabel;
14 @property (weak, nonatomic) IBOutlet UILabel *durationLabel;
15 @property(nonatomic,strong)YYMusicModel *playingMusic;
16 - (IBAction)exit;
17
18 @end
19
20 @implementation YYPlayingViewController
21 #pragma mark-公共方法
22 -(void)show
23 {
24     //1.禁用整个app的点击事件
25     UIWindow *window=[UIApplication sharedApplication].keyWindow;
26     window.userInteractionEnabled=NO;
27
28     //2.添加播放界面
29     //设置View的大小为覆盖整个窗口
30     self.view.frame=window.bounds;
31     //设置view显示
32     self.view.hidden=NO;
33     //把View添加到窗口上
34     [window addSubview:self.view];
35
36     //3.检测是否换了歌曲
37     if (self.playingMusic!=[YYMusicTool playingMusic]) {
38         [self RresetPlayingMusic];
39     }
40
41     //4.使用动画让View显示
42     self.view.y=self.view.height;
43     [UIView animateWithDuration:0.25 animations:^{
44         self.view.y=0;
45     } completion:^(BOOL finished) {
46
47         //设置音乐数据
48         [self starPlayingMusic];
49         window.userInteractionEnabled=YES;
50     }];
51 }
52 #pragma mark-私有方法
53 //重置正在播放的音乐
54 -(void)RresetPlayingMusic
55 {
56     //1.重置界面数据
57     self.iconView.image=[UIImage imageNamed:@"play_cover_pic_bg"];
58     self.songLabel.text=nil;
59     self.singerLabel.text=nil;
60
61     //2.停止播放
62     [YYAudioTool stopMusic:self.playingMusic.filename];
63 }
64 //开始播放音乐数据
65 -(void)starPlayingMusic
66 {
67     //1.设置界面数据
68
69     //取出当前正在播放的音乐
70 //    YYMusicModel *playingMusic=[YYMusicTool playingMusic];
71
72     //如果当前播放的音乐就是传入的音乐,那么就直接返回
73     if (self.playingMusic==[YYMusicTool playingMusic]) return;
74     //存取音乐
75     self.playingMusic=[YYMusicTool playingMusic];
76     self.iconView.image=[UIImage imageNamed:self.playingMusic.icon];
77     self.songLabel.text=self.playingMusic.name;
78     self.singerLabel.text=self.playingMusic.singer;
79
80     //2.开始播放
81     [YYAudioTool playMusic:self.playingMusic.filename];
82
83 }
84
85 #pragma mark-内部的按钮监听方法
86 //返回按钮
87 - (IBAction)exit {
88     //1.禁用整个app的点击事件
89     UIWindow *window=[UIApplication sharedApplication].keyWindow;
90     window.userInteractionEnabled=NO;
91
92     //2.动画隐藏View
93     [UIView animateWithDuration:0.25 animations:^{
94         self.view.y=window.height;
95     } completion:^(BOOL finished) {
96         window.userInteractionEnabled=YES;
97         //设置view隐藏能够节省一些性能
98         self.view.hidden=YES;
99     }];
100 }
101 @end


注意:先让用户看到界面上的所有东西后,再开始播放歌曲。

提示:一般的播放器需要做一个重置的操作。
  当从一首歌切换到另外一首时,应该先把上一首的信息删除,因此在show动画显示之前,应该检测是否换了歌曲,如果换了歌曲,则应该做一次重置操作。
实现效果(能够顺利的切换和播放歌曲,下面是界面显示):







五、补充代码
YYMusicsViewController.m文件

1 //
2 //  YYMusicsViewController.m
3 //
4
5 #import "YYMusicsViewController.h"
6 #import "YYMusicModel.h"
7 #import "MJExtension.h"
8 #import "YYMusicCell.h"
9 #import "YYPlayingViewController.h"
10 #import "YYMusicTool.h"
11
12 @interface YYMusicsViewController ()
13
14 @property(nonatomic,strong)YYPlayingViewController *playingViewController;
15 @end
16
17 @implementation YYMusicsViewController
18 #pragma mark-懒加载
19
20 -(YYPlayingViewController *)playingViewController
21 {
22     if (_playingViewController==nil) {
23         _playingViewController=[[YYPlayingViewController alloc]init];
24     }
25     return _playingViewController;
26 }
27
28 - (void)viewDidLoad
29 {
30     [super viewDidLoad];
31 }
32
33 #pragma mark - Table view data source
34 /**
35  *一共多少组
36  */
37 -(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
38 {
39     return 1;
40 }
41 /**
42  *每组多少行
43  */
44 -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
45 {
46     return [YYMusicTool musics].count;
47 }
48 /**
49  *每组每行的cell
50  */
51 -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
52 {
53     YYMusicCell *cell=[YYMusicCell cellWithTableView:tableView];
54     cell.music=[YYMusicTool musics][indexPath.row];
55     return cell;
56 }
57 /**
58  *  设置每个cell的高度
59  */
60 -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
61 {
62     return 70;
63 }
64
65 /**
66  *  cell的点击事件
67  */
68 -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
69 {
70     //1.取消选中被点击的这行
71     [tableView deselectRowAtIndexPath:indexPath animated:YES];
72
73     //2.设置正在播放的歌曲
74     [YYMusicTool setPlayingMusic:[YYMusicTool musics][indexPath.row]];
75
76     //调用公共方法
77     [self.playingViewController show];
78
79 //    //执行segue跳转
80 //    [self performSegueWithIdentifier:@"music2playing" sender:nil];
81 }
82 @end


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: