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


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

    说明:该文主要介绍音乐播放器实现过程中的一些细节控制。

    实现的效果:

      

    一、完整的代码

    YYPlayingViewController.m文件

    复制代码
      1 //
      2 //  YYPlayingViewController.m
      3 //  20-音频处理(音乐播放器1)
      4 //
      5 //  Created by apple on 14-8-13.
      6 //  Copyright (c) 2014年 yangyong. All rights reserved.
      7 //
      8 
      9 #import "YYPlayingViewController.h"
     10 #import "YYMusicTool.h"
     11 #import "YYMusicModel.h"
     12 #import "YYAudioTool.h"
     13 
     14 @interface YYPlayingViewController ()
     15 //进度条
     16 @property (weak, nonatomic) IBOutlet UIView *progressView;
     17 //滑块
     18 @property (weak, nonatomic) IBOutlet UIButton *slider;
     19 @property (weak, nonatomic) IBOutlet UIImageView *iconView;
     20 @property (weak, nonatomic) IBOutlet UILabel *songLabel;
     21 @property (weak, nonatomic) IBOutlet UILabel *singerLabel;
     22 //当前播放的音乐的时长
     23 @property (weak, nonatomic) IBOutlet UILabel *durationLabel;
     24 //正在播放的音乐
     25 @property(nonatomic,strong)YYMusicModel *playingMusic;
     26 //音乐播放器对象
     27 @property(nonatomic,strong)AVAudioPlayer *player;
     28 //定时器
     29 @property(nonatomic,strong)NSTimer *CurrentTimeTimer;
     30 - (IBAction)exit;
     31 - (IBAction)tapProgressBg:(UITapGestureRecognizer *)sender;
     32 - (IBAction)panSlider:(UIPanGestureRecognizer *)sender;
     33 
     34 @end
     35 
     36 @implementation YYPlayingViewController
     37 #pragma mark-公共方法
     38 -(void)show
     39 {
     40     //1.禁用整个app的点击事件
     41     UIWindow *window=[UIApplication sharedApplication].keyWindow;
     42     window.userInteractionEnabled=NO;
     43     
     44     //2.添加播放界面
     45     //设置View的大小为覆盖整个窗口
     46     self.view.frame=window.bounds;
     47     //设置view显示
     48     self.view.hidden=NO;
     49     //把View添加到窗口上
     50     [window addSubview:self.view];
     51     
     52     //3.检测是否换了歌曲
     53     if (self.playingMusic!=[YYMusicTool playingMusic]) {
     54         [self RresetPlayingMusic];
     55     }
     56     
     57     //4.使用动画让View显示
     58     self.view.y=self.view.height;
     59     [UIView animateWithDuration:0.25 animations:^{
     60         self.view.y=0;
     61     } completion:^(BOOL finished) {
     62         
     63         //设置音乐数据
     64         [self starPlayingMusic];
     65         window.userInteractionEnabled=YES;
     66     }];
     67 }
     68 
     69 
     70 #pragma mark-私有方法
     71 //重置正在播放的音乐
     72 -(void)RresetPlayingMusic
     73 {
     74     //1.重置界面数据
     75     self.iconView.image=[UIImage imageNamed:@"play_cover_pic_bg"];
     76     self.songLabel.text=nil;
     77     self.singerLabel.text=nil;
     78     
     79     //2.停止播放
     80     [YYAudioTool stopMusic:self.playingMusic.filename];
     81     //把播放器进行清空
     82     self.player=nil;
     83     
     84     //3.停止定时器
     85     [self removeCurrentTime];
     86 }
     87 //开始播放音乐数据
     88 -(void)starPlayingMusic
     89 {
     90     //1.设置界面数据
     91     
     92     //如果当前播放的音乐就是传入的音乐,那么就直接返回
     93     if (self.playingMusic==[YYMusicTool playingMusic])
     94     {
     95         //把定时器加进去
     96         [self addCurrentTimeTimer];
     97         return;
     98     }
     99     //存取音乐
    100     self.playingMusic=[YYMusicTool playingMusic];
    101     self.iconView.image=[UIImage imageNamed:self.playingMusic.icon];
    102     self.songLabel.text=self.playingMusic.name;
    103     self.singerLabel.text=self.playingMusic.singer;
    104     
    105     //2.开始播放
    106     self.player = [YYAudioTool playMusic:self.playingMusic.filename];
    107     
    108     //3.设置时长
    109     //self.player.duration;  播放器正在播放的音乐文件的时间长度
    110     self.durationLabel.text=[self strWithTime:self.player.duration];
    111     
    112     //4.添加定时器
    113     [self addCurrentTimeTimer];
    114     
    115 }
    116 
    117 /**
    118  *把时间长度-->时间字符串
    119  */
    120 -(NSString *)strWithTime:(NSTimeInterval)time
    121 {
    122     int minute=time / 60;
    123     int second=(int)time % 60;
    124     return [NSString stringWithFormat:@"%d:%d",minute,second];
    125 }
    126 
    127 #pragma mark-定时器控制
    128 /**
    129  *  添加一个定时器
    130  */
    131 -(void)addCurrentTimeTimer
    132 {
    133     //提前先调用一次进度更新,以保证定时器的工作时及时的
    134     [self updateCurrentTime];
    135     
    136     //创建一个定时器,每一秒钟调用一次
    137     self.CurrentTimeTimer=[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(updateCurrentTime) userInfo:nil repeats:YES];
    138     //把定时器加入到运行时中
    139     [[NSRunLoop mainRunLoop]addTimer:self.CurrentTimeTimer forMode:NSRunLoopCommonModes];
    140 }
    141 /**
    142  *移除一个定时器
    143  */
    144 -(void)removeCurrentTime
    145 {
    146     [self.CurrentTimeTimer invalidate];
    147     
    148     //把定时器清空
    149     self.CurrentTimeTimer=nil;
    150 }
    151 
    152 /**
    153  *  更新播放进度
    154  */
    155 -(void)updateCurrentTime
    156 {
    157     //1.计算进度值
    158     double progress=self.player.currentTime/self.player.duration;
    159     
    160     //2.计算滑块的x值
    161     // 滑块的最大的x值
    162     CGFloat sliderMaxX=self.view.width-self.slider.width;
    163     self.slider.x=sliderMaxX*progress;
    164     //设置滑块上的当前播放时间
    165     [self.slider setTitle:[self strWithTime:self.player.currentTime] forState:UIControlStateNormal];
    166     
    167     //3.设置进度条的宽度
    168     self.progressView.width=self.slider.center.x;
    169     
    170 }
    171 
    172 #pragma mark-内部的按钮监听方法
    173 //返回按钮
    174 - (IBAction)exit {
    175     
    176     //0.移除定时器
    177     [self  removeCurrentTime];
    178     //1.禁用整个app的点击事件
    179     UIWindow *window=[UIApplication sharedApplication].keyWindow;
    180     window.userInteractionEnabled=NO;
    181     
    182     //2.动画隐藏View
    183     [UIView animateWithDuration:0.25 animations:^{
    184         self.view.y=window.height;
    185     } completion:^(BOOL finished) {
    186         window.userInteractionEnabled=YES;
    187         //设置view隐藏能够节省一些性能
    188         self.view.hidden=YES;
    189     }];
    190 }
    191 
    192 /**
    193  *点击了进度条
    194  */
    195 - (IBAction)tapProgressBg:(UITapGestureRecognizer *)sender {
    196     //获取当前单击的点
    197     CGPoint point=[sender locationInView:sender.view];
    198     //切换歌曲的当前播放时间
    199     self.player.currentTime=(point.x/sender.view.width)*self.player.duration;
    200     //更新播放进度
    201     [self updateCurrentTime];
    202 }
    203 
    204 - (IBAction)panSlider:(UIPanGestureRecognizer *)sender {
    205     
    206     //1.获得挪动的距离
    207     CGPoint t=[sender translationInView:sender.view];
    208     //把挪动清零
    209     [sender setTranslation:CGPointZero inView:sender.view];
    210     
    211     //2.控制滑块和进度条的frame
    212     self.slider.x+=t.x;
    213     //设置进度条的宽度
    214     self.progressView.width=self.slider.center.x;
    215     
    216     //3.设置时间值
    217     CGFloat sliderMaxX=self.view.width-self.slider.width;
    218     double progress=self.slider.x/sliderMaxX;
    219     //当前的时间值=音乐的时长*当前的进度值
    220     NSTimeInterval time=self.player.duration*progress;
    221     [self .slider setTitle:[self strWithTime:time] forState:UIControlStateNormal];
    222     
    223     //4.如果开始拖动,那么就停止定时器
    224     if (sender.state==UIGestureRecognizerStateBegan) {
    225         //停止定时器
    226         [self removeCurrentTime];
    227     }else if(sender.state==UIGestureRecognizerStateEnded)
    228     {
    229         //设置播放器播放的时间
    230         self.player.currentTime=time;
    231         //开启定时器
    232         [self addCurrentTimeTimer];
    233     }
    234 }
    235 @end
    复制代码

    二、代码说明(一)

      调整开始播放音乐按钮,让其返回一个音乐播放器,而非BOOL型的。

    复制代码
     1 /**
     2  *播放音乐
     3  */
     4 +(AVAudioPlayer *)playMusic:(NSString *)filename
     5 {
     6     if (!filename) return nil;//如果没有传入文件名,那么直接返回
     7     //1.取出对应的播放器
     8     AVAudioPlayer *player=[self musicPlayers][filename];
     9     
    10     //2.如果播放器没有创建,那么就进行初始化
    11     if (!player) {
    12         //2.1音频文件的URL
    13         NSURL *url=[[NSBundle mainBundle]URLForResource:filename withExtension:nil];
    14         if (!url) return nil;//如果url为空,那么直接返回
    15         
    16         //2.2创建播放器
    17         player=[[AVAudioPlayer alloc]initWithContentsOfURL:url error:nil];
    18         
    19         //2.3缓冲
    20         if (![player prepareToPlay]) return nil;//如果缓冲失败,那么就直接返回
    21         
    22         //2.4存入字典
    23         [self musicPlayers][filename]=player;
    24     }
    25     
    26     //3.播放
    27     if (![player isPlaying]) {
    28         //如果当前没处于播放状态,那么就播放
    29          [player play];
    30     }
    31 
    32     return player;//正在播放,那么就返回YES
    33 }
    复制代码

    三、代码说明(二)

      把时间转换为时间字符串的方法:

    复制代码
    1 /**
    2  *把时间长度-->时间字符串
    3  */
    4 -(NSString *)strWithTime:(NSTimeInterval)time
    5 {
    6     int minute=time / 60;
    7     int second=(int)time % 60;
    8     return [NSString stringWithFormat:@"%d:%d",minute,second];
    9 }
    复制代码

    四、代码说明(三)

      说明:进度控制

      监听当前的播放,使用一个定时器,不断的监听当前是第几秒。

      关于定时器的处理:这里使用了三个方法,分别是添加定时器,移除定时器,和更新播放进度。

    注意细节:

    (1)移除定时器后,对定时器进行清空处理。

    复制代码
     1 /**
     2  *移除一个定时器
     3  */
     4 -(void)removeCurrentTime
     5 {
     6     [self.CurrentTimeTimer invalidate];
     7     
     8     //把定时器清空
     9     self.CurrentTimeTimer=nil;
    10 }
    复制代码

    (2)当看不到界面的时候,停止定时器。

    (3)在开始播放音乐的方法中进行判断,如果当前播放的音乐和传入的音乐一致,那么添加定时器后直接返回。

    (4)重置播放的音乐方法中,停止定时器。

    五、代码说明(四)

      说明:点击和拖动进度条的处理

    1.点击进度条

      先添加单击的手势识别器。

        

      往控制器拖线:

        

    涉及的代码:

    复制代码
     1 /**
     2  *点击了进度条
     3  */
     4 - (IBAction)tapProgressBg:(UITapGestureRecognizer *)sender {
     5     //获取当前单击的点
     6     CGPoint point=[sender locationInView:sender.view];
     7     //切换歌曲的当前播放时间
     8     self.player.currentTime=(point.x/sender.view.width)*self.player.duration;
     9     //更新播放进度
    10     [self updateCurrentTime];
    11 }
    复制代码

    2.拖拽进度条

      先添加拖拽手势识别器

      

    往控制器拖线

      

    涉及的代码:

    复制代码
     1 /**
     2  *拖动滑块
     3  */
     4 - (IBAction)panSlider:(UIPanGestureRecognizer *)sender {
     5     
     6     //1.获得挪动的距离
     7     CGPoint t=[sender translationInView:sender.view];
     8     //把挪动清零
     9     [sender setTranslation:CGPointZero inView:sender.view];
    10     
    11     //2.控制滑块和进度条的frame
    12     self.slider.x+=t.x;
    13     //设置进度条的宽度
    14     self.progressView.width=self.slider.center.x;
    15     
    16     //3.设置时间值
    17     CGFloat sliderMaxX=self.view.width-self.slider.width;
    18     double progress=self.slider.x/sliderMaxX;
    19     //当前的时间值=音乐的时长*当前的进度值
    20     NSTimeInterval time=self.player.duration*progress;
    21     [self .slider setTitle:[self strWithTime:time] forState:UIControlStateNormal];
    22     
    23     //4.如果开始拖动,那么就停止定时器
    24     if (sender.state==UIGestureRecognizerStateBegan) {
    25         //停止定时器
    26         [self removeCurrentTime];
    27     }else if(sender.state==UIGestureRecognizerStateEnded)
    28     {
    29         //设置播放器播放的时间
    30         self.player.currentTime=time;
    31         //开启定时器
    32         [self addCurrentTimeTimer];
    33     }
    34 }
    复制代码

     

     
  • 相关阅读:
    分布式版本控制系统Git-----5.Git 的push命令总结
    分布式版本控制系统Git-----4.Git 常用命令整理
    分布式版本控制系统Git-----3.图形化Tortoisegit创建本地库并且提交到远程服务器上
    分布式版本控制系统Git-----2.上传至远程仓库之基础版
    分布式版本控制系统Git-----1.Git 初识
    JavaWeb笔记03-Servlet
    JavaWeb笔记01-XML
    Emmet的html语法
    npm常用命令
    Node.js中事件的循环
  • 原文地址:https://www.cnblogs.com/sunflower-lhb/p/4914827.html
Copyright © 2020-2023  润新知