一、控制器间数据传递
两个控制器之间数据的传递
第一种方法:
self.parentViewController.music=self.music[indexPath.row];不能满足
工具类中的代码设计如下:
YYMusicTool.h文件 // // YYMusicTool.h //#import <Foundation/Foundation.h> @class YYMusicModel; @interface YYMusicTool : NSObject /** * 返回所有的歌曲 */ + (NSArray *)musics;
/** * 返回正在播放的歌曲 */ + (YYMusicModel *)playingMusic; + (void)setPlayingMusic:(YYMusicModel *)playingMusic;
/** * 下一首歌曲 */ + (YYMusicModel *)nextMusic;
/** * 上一首歌曲 */ + (YYMusicModel *)previousMusic; @end
// // YYMusicTool.m //#import "YYMusicTool.h" #import "YYMusicModel.h" #import "MJExtension.h"
@implementation YYMusicTool
static NSArray *_musics; static YYMusicModel *_playingMusic;
/** * @return 返回所有的歌曲 */ +(NSArray *)musics { if (_musics==nil) { _musics=[YYMusicModel objectArrayWithFilename:@"Musics.plist"]; } return _musics; }
+(void)setPlayingMusic:(YYMusicModel *)playingMusic { /* *如果没有传入需要播放的歌曲,或者是传入的歌曲名不在音乐库中,那么就直接返回 如果需要播放的歌曲就是当前正在播放的歌曲,那么直接返回 */ if (!playingMusic || ![[self musics]containsObject:playingMusic]) return; if (_playingMusic == playingMusic) return; _playingMusic=playingMusic; } /** * 返回正在播放的歌曲 */ +(YYMusicModel *)playingMusic { return _playingMusic; }
/** * 下一首歌曲 */ +(YYMusicModel *)nextMusic { //设定一个初值 int nextIndex = 0; if (_playingMusic) { //获取当前播放音乐的索引 int playingIndex = [[self musics] indexOfObject:_playingMusic]; //设置下一首音乐的索引 nextIndex = playingIndex+1; //检查数组越界,如果下一首音乐是最后一首,那么重置为0 if (nextIndex>=[self musics].count) { nextIndex=0; } } return [self musics][nextIndex]; }
/** * 上一首歌曲 */ +(YYMusicModel *)previousMusic { //设定一个初值 int previousIndex = 0; if (_playingMusic) { //获取当前播放音乐的索引 int playingIndex = [[self musics] indexOfObject:_playingMusic]; //设置下一首音乐的索引 previousIndex = playingIndex-1; //检查数组越界,如果下一首音乐是最后一首,那么重置为0 if (previousIndex<0) { previousIndex=[self musics].count-1; } } return [self musics][previousIndex]; } @end
该工具类中的代码设计如下:
YYAudioTool.h文件
// // YYAudioTool.h //#import <Foundation/Foundation.h> #import <AVFoundation/AVFoundation.h> @interface YYAudioTool : NSObject /** *播放音乐文件 */ +(BOOL)playMusic:(NSString *)filename; /** *暂停播放 */ +(void)pauseMusic:(NSString *)filename; /** *播放音乐文件 */ +(void)stopMusic:(NSString *)filename;
/** *播放音效文件 */ +(void)playSound:(NSString *)filename; /** *销毁音效 */ +(void)disposeSound:(NSString *)filename; @end
// // YYAudioTool.m //#import "YYAudioTool.h"
@implementation YYAudioTool /** *存放所有的音乐播放器 */ static NSMutableDictionary *_musicPlayers; +(NSMutableDictionary *)musicPlayers { if (_musicPlayers==nil) { _musicPlayers=[NSMutableDictionary dictionary]; } return _musicPlayers; }
/** *存放所有的音效ID */ static NSMutableDictionary *_soundIDs; +(NSMutableDictionary *)soundIDs { if (_soundIDs==nil) { _soundIDs=[NSMutableDictionary dictionary]; } return _soundIDs; }
/** *播放音乐 */ +(BOOL)playMusic:(NSString *)filename { if (!filename) return NO;//如果没有传入文件名,那么直接返回 //1.取出对应的播放器 AVAudioPlayer *player=[self musicPlayers][filename]; //2.如果播放器没有创建,那么就进行初始化 if (!player) { //2.1音频文件的URL NSURL *url=[[NSBundle mainBundle]URLForResource:filename withExtension:nil]; if (!url) return NO;//如果url为空,那么直接返回 //2.2创建播放器 player=[[AVAudioPlayer alloc]initWithContentsOfURL:url error:nil]; //2.3缓冲 if (![player prepareToPlay]) return NO;//如果缓冲失败,那么就直接返回 //2.4存入字典 [self musicPlayers][filename]=player; } //3.播放 if (![player isPlaying]) { //如果当前没处于播放状态,那么就播放 return [player play]; }
return YES;//正在播放,那么就返回YES }
+(void)pauseMusic:(NSString *)filename { if (!filename) return;//如果没有传入文件名,那么就直接返回 //1.取出对应的播放器 AVAudioPlayer *player=[self musicPlayers][filename]; //2.暂停 [player pause];//如果palyer为空,那相当于[nil pause],因此这里可以不用做处理
}
+(void)stopMusic:(NSString *)filename { if (!filename) return;//如果没有传入文件名,那么就直接返回 //1.取出对应的播放器 AVAudioPlayer *player=[self musicPlayers][filename]; //2.停止 [player stop]; //3.将播放器从字典中移除 [[self musicPlayers] removeObjectForKey:filename]; }
//播放音效 +(void)playSound:(NSString *)filename { if (!filename) return; //1.取出对应的音效 SystemSoundID soundID=[[self soundIDs][filename] unsignedIntegerValue]; //2.播放音效 //2.1如果音效ID不存在,那么就创建 if (!soundID) { //音效文件的URL NSURL *url=[[NSBundle mainBundle]URLForResource:filename withExtension:nil]; if (!url) return;//如果URL不存在,那么就直接返回 OSStatus status = AudioServicesCreateSystemSoundID((__bridge CFURLRef)(url), &soundID); NSLog(@"%ld",status); //存入到字典中 [self soundIDs][filename]=@(soundID); } //2.2有音效ID后,播放音效 AudioServicesPlaySystemSound(soundID); }
//销毁音效 +(void)disposeSound:(NSString *)filename { //如果传入的文件名为空,那么就直接返回 if (!filename) return; //1.取出对应的音效 SystemSoundID soundID=[[self soundIDs][filename] unsignedIntegerValue]; //2.销毁 if (soundID) { AudioServicesDisposeSystemSoundID(soundID); //2.1销毁后,从字典中移除 [[self soundIDs]removeObjectForKey:filename]; } } @end
YYPlayingViewController.m文件
// // YYPlayingViewController.m //#import "YYPlayingViewController.h" #import "YYMusicTool.h" #import "YYMusicModel.h" #import "YYAudioTool.h"
@interface YYPlayingViewController () @property (weak, nonatomic) IBOutlet UIImageView *iconView; @property (weak, nonatomic) IBOutlet UILabel *songLabel; @property (weak, nonatomic) IBOutlet UILabel *singerLabel; @property (weak, nonatomic) IBOutlet UILabel *durationLabel; @property(nonatomic,strong)YYMusicModel *playingMusic; - (IBAction)exit;
@end
@implementation YYPlayingViewController #pragma mark-公共方法 -(void)show { //1.禁用整个app的点击事件 UIWindow *window=[UIApplication sharedApplication].keyWindow; window.userInteractionEnabled=NO; //2.添加播放界面 //设置View的大小为覆盖整个窗口 self.view.frame=window.bounds; //设置view显示 self.view.hidden=NO; //把View添加到窗口上 [window addSubview:self.view]; //3.检测是否换了歌曲 if (self.playingMusic!=[YYMusicTool playingMusic]) { [self RresetPlayingMusic]; } //4.使用动画让View显示 self.view.y=self.view.height; [UIView animateWithDuration:0.25 animations:^{ self.view.y=0; } completion:^(BOOL finished) { //设置音乐数据 [self starPlayingMusic]; window.userInteractionEnabled=YES; }]; } #pragma mark-私有方法 //重置正在播放的音乐 -(void)RresetPlayingMusic { //1.重置界面数据 self.iconView.image=[UIImage imageNamed:@"play_cover_pic_bg"]; self.songLabel.text=nil; self.singerLabel.text=nil; //2.停止播放 [YYAudioTool stopMusic:self.playingMusic.filename]; } //开始播放音乐数据 -(void)starPlayingMusic { //1.设置界面数据 //取出当前正在播放的音乐 // YYMusicModel *playingMusic=[YYMusicTool playingMusic]; //如果当前播放的音乐就是传入的音乐,那么就直接返回 if (self.playingMusic==[YYMusicTool playingMusic]) return; //存取音乐 self.playingMusic=[YYMusicTool playingMusic]; self.iconView.image=[UIImage imageNamed:self.playingMusic.icon]; self.songLabel.text=self.playingMusic.name; self.singerLabel.text=self.playingMusic.singer; //2.开始播放 [YYAudioTool playMusic:self.playingMusic.filename]; }#pragma mark-内部的按钮监听方法 //返回按钮 - (IBAction)exit { //1.禁用整个app的点击事件 UIWindow *window=[UIApplication sharedApplication].keyWindow; window.userInteractionEnabled=NO; //2.动画隐藏View [UIView animateWithDuration:0.25 animations:^{ self.view.y=window.height; } completion:^(BOOL finished) { window.userInteractionEnabled=YES; //设置view隐藏能够节省一些性能 self.view.hidden=YES; }]; } @end
提示:一般的播放器需要做一个重置的操作。
当从一首歌切换到另外一首时,应该先把上一首的信息删除,因此在show动画显示之前,应该检测是否换了歌曲,如果换了歌曲,则应该做一次重置操作。
实现效果(能够顺利的切换和播放歌曲,下面是界面显示):
五、补充代码
YYMusicsViewController.m文件
// // YYMusicsViewController.m //#import "YYMusicsViewController.h" #import "YYMusicModel.h" #import "MJExtension.h" #import "YYMusicCell.h" #import "YYPlayingViewController.h" #import "YYMusicTool.h"
@interface YYMusicsViewController ()
@property(nonatomic,strong)YYPlayingViewController *playingViewController; @end
@implementation YYMusicsViewController #pragma mark-懒加载-(YYPlayingViewController *)playingViewController { if (_playingViewController==nil) { _playingViewController=[[YYPlayingViewController alloc]init]; } return _playingViewController; }
- (void)viewDidLoad { [super viewDidLoad]; }
#pragma mark - Table view data source /** *一共多少组 */ -(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return 1; } /** *每组多少行 */ -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return [YYMusicTool musics].count; } /** *每组每行的cell */ -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { YYMusicCell *cell=[YYMusicCell cellWithTableView:tableView]; cell.music=[YYMusicTool musics][indexPath.row]; return cell; } /** * 设置每个cell的高度 */ -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { return 70; }
/** * cell的点击事件 */ -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { //1.取消选中被点击的这行 [tableView deselectRowAtIndexPath:indexPath animated:YES]; //2.设置正在播放的歌曲 [YYMusicTool setPlayingMusic:[YYMusicTool musics][indexPath.row]];
//调用公共方法 [self.playingViewController show]; // //执行segue跳转 // [self performSegueWithIdentifier:@"music2playing" sender:nil]; } @end
完整的代码
YYPlayingViewController.m文件
// // YYPlayingViewController.m // 20-音频处理(音乐播放器1) // // Created by apple on 14-8-13. // Copyright (c) 2014年 yangyong. All rights reserved. //#import "YYPlayingViewController.h" #import "YYMusicTool.h" #import "YYMusicModel.h" #import "YYAudioTool.h"
@interface YYPlayingViewController () //进度条 @property (weak, nonatomic) IBOutlet UIView *progressView; //滑块 @property (weak, nonatomic) IBOutlet UIButton *slider; @property (weak, nonatomic) IBOutlet UIImageView *iconView; @property (weak, nonatomic) IBOutlet UILabel *songLabel; @property (weak, nonatomic) IBOutlet UILabel *singerLabel; //当前播放的音乐的时长 @property (weak, nonatomic) IBOutlet UILabel *durationLabel; //正在播放的音乐 @property(nonatomic,strong)YYMusicModel *playingMusic; //音乐播放器对象 @property(nonatomic,strong)AVAudioPlayer *player; //定时器 @property(nonatomic,strong)NSTimer *CurrentTimeTimer; - (IBAction)exit; - (IBAction)tapProgressBg:(UITapGestureRecognizer *)sender; - (IBAction)panSlider:(UIPanGestureRecognizer *)sender;
@end
@implementation YYPlayingViewController #pragma mark-公共方法 -(void)show { //1.禁用整个app的点击事件 UIWindow *window=[UIApplication sharedApplication].keyWindow; window.userInteractionEnabled=NO; //2.添加播放界面 //设置View的大小为覆盖整个窗口 self.view.frame=window.bounds; //设置view显示 self.view.hidden=NO; //把View添加到窗口上 [window addSubview:self.view]; //3.检测是否换了歌曲 if (self.playingMusic!=[YYMusicTool playingMusic]) { [self RresetPlayingMusic]; } //4.使用动画让View显示 self.view.y=self.view.height; [UIView animateWithDuration:0.25 animations:^{ self.view.y=0; } completion:^(BOOL finished) { //设置音乐数据 [self starPlayingMusic]; window.userInteractionEnabled=YES; }]; }#pragma mark-私有方法 //重置正在播放的音乐 -(void)RresetPlayingMusic { //1.重置界面数据 self.iconView.image=[UIImage imageNamed:@"play_cover_pic_bg"]; self.songLabel.text=nil; self.singerLabel.text=nil; //2.停止播放 [YYAudioTool stopMusic:self.playingMusic.filename]; //把播放器进行清空 self.player=nil; //3.停止定时器 [self removeCurrentTime]; } //开始播放音乐数据 -(void)starPlayingMusic { //1.设置界面数据 //如果当前播放的音乐就是传入的音乐,那么就直接返回 if (self.playingMusic==[YYMusicTool playingMusic]) { //把定时器加进去 [self addCurrentTimeTimer]; return; } //存取音乐 self.playingMusic=[YYMusicTool playingMusic]; self.iconView.image=[UIImage imageNamed:self.playingMusic.icon]; self.songLabel.text=self.playingMusic.name; self.singerLabel.text=self.playingMusic.singer; //2.开始播放 self.player = [YYAudioTool playMusic:self.playingMusic.filename]; //3.设置时长 //self.player.duration; 播放器正在播放的音乐文件的时间长度 self.durationLabel.text=[self strWithTime:self.player.duration]; //4.添加定时器 [self addCurrentTimeTimer]; }
/** *把时间长度-->时间字符串 */ -(NSString *)strWithTime:(NSTimeInterval)time { int minute=time / 60; int second=(int)time % 60; return [NSString stringWithFormat:@"%d:%d",minute,second]; }
#pragma mark-定时器控制 /** * 添加一个定时器 */ -(void)addCurrentTimeTimer { //提前先调用一次进度更新,以保证定时器的工作时及时的 [self updateCurrentTime]; //创建一个定时器,每一秒钟调用一次 self.CurrentTimeTimer=[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(updateCurrentTime) userInfo:nil repeats:YES]; //把定时器加入到运行时中 [[NSRunLoop mainRunLoop]addTimer:self.CurrentTimeTimer forMode:NSRunLoopCommonModes]; } /** *移除一个定时器 */ -(void)removeCurrentTime { [self.CurrentTimeTimer invalidate]; //把定时器清空 self.CurrentTimeTimer=nil; }
/** * 更新播放进度 */ -(void)updateCurrentTime { //1.计算进度值 double progress=self.player.currentTime/self.player.duration; //2.计算滑块的x值 // 滑块的最大的x值 CGFloat sliderMaxX=self.view.width-self.slider.width; self.slider.x=sliderMaxX*progress; //设置滑块上的当前播放时间 [self.slider setTitle:[self strWithTime:self.player.currentTime] forState:UIControlStateNormal]; //3.设置进度条的宽度 self.progressView.width=self.slider.center.x; }
#pragma mark-内部的按钮监听方法 //返回按钮 - (IBAction)exit { //0.移除定时器 [self removeCurrentTime]; //1.禁用整个app的点击事件 UIWindow *window=[UIApplication sharedApplication].keyWindow; window.userInteractionEnabled=NO; //2.动画隐藏View [UIView animateWithDuration:0.25 animations:^{ self.view.y=window.height; } completion:^(BOOL finished) { window.userInteractionEnabled=YES; //设置view隐藏能够节省一些性能 self.view.hidden=YES; }]; }
/** *点击了进度条 */ - (IBAction)tapProgressBg:(UITapGestureRecognizer *)sender { //获取当前单击的点 CGPoint point=[sender locationInView:sender.view]; //切换歌曲的当前播放时间 self.player.currentTime=(point.x/sender.view.width)*self.player.duration; //更新播放进度 [self updateCurrentTime]; }
- (IBAction)panSlider:(UIPanGestureRecognizer *)sender { //1.获得挪动的距离 CGPoint t=[sender translationInView:sender.view]; //把挪动清零 [sender setTranslation:CGPointZero inView:sender.view]; //2.控制滑块和进度条的frame self.slider.x+=t.x; //设置进度条的宽度 self.progressView.width=self.slider.center.x; //3.设置时间值 CGFloat sliderMaxX=self.view.width-self.slider.width; double progress=self.slider.x/sliderMaxX; //当前的时间值=音乐的时长*当前的进度值 NSTimeInterval time=self.player.duration*progress; [self .slider setTitle:[self strWithTime:time] forState:UIControlStateNormal]; //4.如果开始拖动,那么就停止定时器 if (sender.state==UIGestureRecognizerStateBegan) { //停止定时器 [self removeCurrentTime]; }else if(sender.state==UIGestureRecognizerStateEnded) { //设置播放器播放的时间 self.player.currentTime=time; //开启定时器 [self addCurrentTimeTimer]; } } @end
调整开始播放音乐按钮,让其返回一个音乐播放器,而非BOOL型的。
/** *播放音乐 */ +(AVAudioPlayer *)playMusic:(NSString *)filename { if (!filename) return nil;//如果没有传入文件名,那么直接返回 //1.取出对应的播放器 AVAudioPlayer *player=[self musicPlayers][filename]; //2.如果播放器没有创建,那么就进行初始化 if (!player) { //2.1音频文件的URL NSURL *url=[[NSBundle mainBundle]URLForResource:filename withExtension:nil]; if (!url) return nil;//如果url为空,那么直接返回 //2.2创建播放器 player=[[AVAudioPlayer alloc]initWithContentsOfURL:url error:nil]; //2.3缓冲 if (![player prepareToPlay]) return nil;//如果缓冲失败,那么就直接返回 //2.4存入字典 [self musicPlayers][filename]=player; } //3.播放 if (![player isPlaying]) { //如果当前没处于播放状态,那么就播放 [player play]; }return player;//正在播放,那么就返回YES }
把时间转换为时间字符串的方法:
/** *把时间长度-->时间字符串 */ -(NSString *)strWithTime:(NSTimeInterval)time { int minute=time / 60; int second=(int)time % 60; return [NSString stringWithFormat:@"%d:%d",minute,second]; }
说明:进度控制
监听当前的播放,使用一个定时器,不断的监听当前是第几秒。
关于定时器的处理:这里使用了三个方法,分别是添加定时器,移除定时器,和更新播放进度。
注意细节:
(1)移除定时器后,对定时器进行清空处理。
/** *移除一个定时器 */ -(void)removeCurrentTime { [self.CurrentTimeTimer invalidate]; //把定时器清空 self.CurrentTimeTimer=nil; }
(3)在开始播放音乐的方法中进行判断,如果当前播放的音乐和传入的音乐一致,那么添加定时器后直接返回。
(4)重置播放的音乐方法中,停止定时器。
代码说明(四)
说明:点击和拖动进度条的处理
(1)点击进度条
先添加单击的手势识别器。
往控制器拖线:
涉及的代码:
/** *点击了进度条 */ - (IBAction)tapProgressBg:(UITapGestureRecognizer *)sender { //获取当前单击的点 CGPoint point=[sender locationInView:sender.view]; //切换歌曲的当前播放时间 self.player.currentTime=(point.x/sender.view.width)*self.player.duration; //更新播放进度 [self updateCurrentTime]; }
先添加拖拽手势识别器
往控制器拖线
涉及的代码:
/** *拖动滑块 */ - (IBAction)panSlider:(UIPanGestureRecognizer *)sender { //1.获得挪动的距离 CGPoint t=[sender translationInView:sender.view]; //把挪动清零 [sender setTranslation:CGPointZero inView:sender.view]; //2.控制滑块和进度条的frame self.slider.x+=t.x; //设置进度条的宽度 self.progressView.width=self.slider.center.x; //3.设置时间值 CGFloat sliderMaxX=self.view.width-self.slider.width; double progress=self.slider.x/sliderMaxX; //当前的时间值=音乐的时长*当前的进度值 NSTimeInterval time=self.player.duration*progress; [self .slider setTitle:[self strWithTime:time] forState:UIControlStateNormal]; //4.如果开始拖动,那么就停止定时器 if (sender.state==UIGestureRecognizerStateBegan) { //停止定时器 [self removeCurrentTime]; }else if(sender.state==UIGestureRecognizerStateEnded) { //设置播放器播放的时间 self.player.currentTime=time; //开启定时器 [self addCurrentTimeTimer]; } }
用ios自带的AVAudio实现的音乐播放器。可以播放存放在电脑里面的音乐文件,可以调整声音音量。播放的时候界面会有下雪的效果。可以作为练习动画和音频播放的例子。 [Code4App.com]
如何控制Android或任何其他播放器的默认音乐播放器?通过控制,我的意思是暂停,播放,下一个等等。我必须绑定服务吗?我尝试使用,但它不起作用。当然有出路,因为我在Android市场上看到了控制音乐播放器的应用程序。任何想法?
本文向大家介绍Android开发简易音乐播放器,包括了Android开发简易音乐播放器的使用技巧和注意事项,需要的朋友参考一下 这里介绍一个简易的音乐播放器,供大家参考,具体内容如下 效果图如下: 但是,由于这是一个简易版的音乐播放器,所播放的音乐只有一首,且被写死,但,操作却十分简单,方便理解! 这是代码的主要设计: 音乐主要存放在这一个文件中: 下面就来介绍各部分代码: activity—ma
我有listview,它包含一个带有播放按钮和搜索栏的音频文件列表。 当我单击listview的播放按钮时,我想播放一个音频文件。我成功地实现了这一点,但当我单击列表中的另一个播放按钮时,两个音频文件正在连续播放,它将继续所有单击播放按钮。我如何限制媒体播放器在一个位置播放,如果我点击另一个图标,它必须停止旧的媒体播放器,并开始播放新的。有人能说我怎么实现这个吗?。我有相同的按钮播放和暂停。
本文向大家介绍iOS开发实现音频播放功能,包括了iOS开发实现音频播放功能的使用技巧和注意事项,需要的朋友参考一下 音频播放 1、介绍 - 功能介绍 用于播放比较长的音频、说明、音乐 ,使用到的是AVFoundation - 框架介绍 * AVAudioPlayer * 初始化: 注意 : (3)必须声明全局变量的音乐播放对象、或者是属性的音乐播放对象 才可以播放 (4)在退出播放页
基于jPlyer开发的音乐播放插件. 支持如下功能: 1,进度条播放 。 2,上一首,下一首,随机播放 。 3,播放完每一首后,自动播放下一首,如果下一首是最后一首,则自动播放第一首。 4,支持鼠标滚动操作,能上下翻滚屏幕。 5,歌曲时间 倒计时 ,而不是从0开始计时。 效果演示地址: http://www.cssrain.cn/jPlayer/jPlayerV2.0/demo.html