iOS 音乐
这篇博客介绍的是较长的音频播放-音乐...
有关音效的介绍可以点击下面的连接进入...首先导入框架:AVFoundation.framework
导入框架后我们在需要使用音乐的文件内引入头文件:
#import
做好准备后开始介绍这篇博客的主要内容:
我在这里实现了一个特别小的功能(如图)
- 可以播放,暂停与停止(分别由三个按钮实现)
- 播放进度的slider可以显示当前播放进度,并且通过拖动实现播放进度的改变
- 播放速度的slider可以改变音乐的播放速度
- 播放音量的slider可以改变音乐的播放音量
下面我会根据每个内容逐个介绍,从而实现整个代码:
AVAudioPlayer
AVAudioPlayer可以说是整个音乐的操作者,通过他我们实现各个操作.
@property (nonatomic, strong) AVAudioPlayer * player;
我们在AVAudioPlayer的懒加载中做一些操作
- (AVAudioPlayer *)player{ if (!_player) { NSURL * url = [[NSBundle mainBundle]URLForResource:@"CX" withExtension:@"mp3"]; NSError * error; //实例化播放 _player = [[AVAudioPlayer alloc]initWithContentsOfURL:url error:&error]; //设置代理 _player.delegate = self; if (error) { NSLog(@"初始化失败"); }else{ //准备开始播放 缓冲数据 [_player prepareToPlay]; //是否允许快播 _player.enableRate = YES; //设置播放次数 -1为无限 //0:播放一次 1:播放两次 ...... _player.numberOfLoops = 0; //slider最大值 self.timeSlider.maximumValue = _player.duration; } } return _player;}
这里值得注意的是准备开始播放 (其他的就不过多说了代码里有着详细的介绍)
即:[_player prepareToPlay];
没有这句是无法正常播放的.
播放
代码操作:
//播放- (IBAction)play:(id)sender { if (![self.player isPlaying]) { //添加定时器到runloop中 [self.link addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode]; [self.player play]; } }
在播放操作中我们进行了是否在播放的判断,以避免混音.
定时器是为了对播放进度的实现,后面会介绍到.暂停
代码操作:
//暂停- (IBAction)pause:(id)sender { if ([self.player isPlaying]) { [self.player pause]; //暂停link [self.link invalidate]; self.link = nil; } }
在暂停操作中我们先判断是否正在播放,只有正在播放才能执行暂停.
暂停的时候为了避免资源的过多浪费我们定制定时器并把定时器清空.停止播放
代码操作:
//停止- (IBAction)stop:(id)sender { [self.player stop]; //清空内存 self.player = nil; //停止link [self.link invalidate]; self.link = nil;}
在停止操作中有一点很值得注意,当我们停止后,再次点击播放会发现是继续播放,显然不符合情理.
因此我们在这里对player进行了清空操作. 定时器的操作如暂停.播放进度slider
播放进度slider的实现是需要配合定时器的使用的("实时"监控),因此前面出现的定时器也就可以理解
了.//定时器的属性声明
//定时器@property (nonatomic, strong) CADisplayLink * link;
//定时器的懒加载
- (CADisplayLink *)link{ if (!_link) { _link = [CADisplayLink displayLinkWithTarget:self selector:@selector(change)]; } return _link;}//改变slider进度的方法- (void)change{ //获取当前时间 重置播放进度 self.timeSlider.value = self.player.currentTime;}
该功能分析:
实现的功能是拖动控件实现进度跳转
那么
- 当我们点击的时候停止播放
- 根据value值设置进度
- 当我们结束拖动时继续播放
代码操作:
//按下slieder 开始拖拽- (IBAction)timeTouchDown:(id)sender { //停止播放 [self.player pause]; }//结束拖拽- (IBAction)timeTouchUp:(id)sender { //继续播放 [self.player play];}//改变播放进度- (IBAction)timeChangeSlider:(UISlider *)sender { //修改现在的播放时间 self.player.currentTime = sender.value;}
播放速度
代码操作:
//播放速度- (IBAction)rateChange:(UISlider *)sender { self.player.rate = sender.value;}
播放音量
代码操作:
//播放音量- (IBAction)voiceChange:(UISlider *)sender { self.player.volume = sender.value;}
代理
//播放完成- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag{ }//error- (void)audioPlayerDecodeErrorDidOccur:(AVAudioPlayer *)player error:(NSError *)error{ }//iOS8 开始中断- (void)audioPlayerBeginInterruption:(AVAudioPlayer *)player{ }//iOS8 结束中断- (void)audioPlayerEndInterruption:(AVAudioPlayer *)player{ }
在上面可以到iOS8的字样
那么iOS9呢???- (void)viewDidLoad { [super viewDidLoad]; //iOS9处理中断 AVAudioSession * session = [AVAudioSession sharedInstance]; [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(Interruption:) name:AVAudioSessionInterruptionNotification object:session]; }//iOS9中断处理方法- (void)Interruption:(NSNotification *)noti{ if (noti.userInfo.allKeys.count == 2) { NSLog(@"结束中断"); }else{ NSLog(@"开始中断"); }}
一页的代码就把代码贴上了
//// ViewController.m// 音乐//// Created by ma c on 16/5/11.// Copyright © 2016年 xubaoaichiyu. All rights reserved.//#import "ViewController.h"#import@interface ViewController () //播放本地音乐@property (nonatomic, strong) AVAudioPlayer * player;//播放时间的滑块@property (weak, nonatomic) IBOutlet UISlider *timeSlider;//定时器@property (nonatomic, strong) CADisplayLink * link;@end@implementation ViewController#pragma mark - - (CADisplayLink *)link{ if (!_link) { _link = [CADisplayLink displayLinkWithTarget:self selector:@selector(change)]; } return _link;}- (AVAudioPlayer *)player{ if (!_player) { NSURL * url = [[NSBundle mainBundle]URLForResource:@"CX" withExtension:@"mp3"]; NSError * error; //实例化播放 _player = [[AVAudioPlayer alloc]initWithContentsOfURL:url error:&error]; //设置代理 _player.delegate = self; if (error) { NSLog(@"初始化失败"); }else{ //准备开始播放 缓冲数据 [_player prepareToPlay]; //是否允许快播 _player.enableRate = YES; //设置播放次数 -1为无限 //0:播放一次 1:播放两次 ...... _player.numberOfLoops = 0; //slider最大值 self.timeSlider.maximumValue = _player.duration; } } return _player;}#pragma mark - - (void)viewDidLoad { [super viewDidLoad]; //iOS9处理中断 AVAudioSession * session = [AVAudioSession sharedInstance]; [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(Interruption:) name:AVAudioSessionInterruptionNotification object:session]; }#pragma mark - //播放完成- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag{ }//error- (void)audioPlayerDecodeErrorDidOccur:(AVAudioPlayer *)player error:(NSError *)error{ }//iOS8 开始中断- (void)audioPlayerBeginInterruption:(AVAudioPlayer *)player{ }//iOS8 结束中断- (void)audioPlayerEndInterruption:(AVAudioPlayer *)player{ }#pragma mark - //改变slider进度的方法- (void)change{ //获取当前时间 重置播放进度 self.timeSlider.value = self.player.currentTime;}//iOS9中断处理方法- (void)Interruption:(NSNotification *)noti{ if (noti.userInfo.allKeys.count == 2) { NSLog(@"结束中断"); }else{ NSLog(@"开始中断"); }}//播放- (IBAction)play:(id)sender { if (![self.player isPlaying]) { //添加定时器到runloop中 [self.link addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode]; [self.player play]; } }//暂停- (IBAction)pause:(id)sender { if ([self.player isPlaying]) { [self.player pause]; //暂停link [self.link invalidate]; self.link = nil; } }//停止- (IBAction)stop:(id)sender { [self.player stop]; //清空内存 self.player = nil; //停止link [self.link invalidate]; self.link = nil;}//按下slieder 开始拖拽- (IBAction)timeTouchDown:(id)sender { //停止播放 [self.player pause]; }//结束拖拽- (IBAction)timeTouchUp:(id)sender { //继续播放 [self.player play];}//改变播放进度- (IBAction)timeChangeSlider:(UISlider *)sender { //修改现在的播放时间 self.player.currentTime = sender.value;}//播放速度- (IBAction)rateChange:(UISlider *)sender { self.player.rate = sender.value;}//播放音量- (IBAction)voiceChange:(UISlider *)sender { self.player.volume = sender.value;}@end