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


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

    一、图片处理

    说明:

    Aspect表示按照原来的宽高比进行缩放。
    Aspectfit表示按照原来的宽高比缩放,要求看到全部图片,后果是不能完全覆盖窗口,会留有空白。
    Aspectfill表示按照原来的宽高比缩放,但只能看到部分图片。引发的问题:可能会有一部分超出屏幕。
    所以,如果选择了Aspectfill模式,那么需要剪切超出的图片,在storyboard中也可以进行设置。
    下面的两种设置是等效的。
    (1)在storyboard中进行设置
    (2)使用代码裁剪

     

    二、播放处理
    1.当前歌曲播放结束之后,继续播放后面的歌曲
      解决方案:成为播放器的代理。监听播放器的播放。
    2.播放中断处理
    #pragma mark-音乐播放器的代理
    //播放器播放完毕后就会调用该方法
    -(void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag
    {
        [self next];
    }
    //当播放器遇到中断的时候(如来电),调用该方法
    -(void)audioPlayerBeginInterruption:(AVAudioPlayer *)player
    {
        if (self.player.isPlaying) {
            //如果当前正在播放,那么就暂停
            [self playOrPause];
        }
    }
    //中断事件结束后调用下面的方法
    -(void)audioPlayerEndInterruption:(AVAudioPlayer *)player withOptions:(NSUInteger)flags
    {
        //可以什么都不做,让用户决定是继续播放还是暂停
    }
    3.开启后台任务
      说明:新的问题——当播放任务进入到后台运行的时候,音乐的播放会停止。
      解决方案:

      YYAppDelegate.m文件中的代码处理如下:

    争取更多的机会:

     

    告诉其是一个音乐播放任务

     

    4.最好是在音频播放工具类中也进行处理。

    #import "YYAudioTool.h"
    
    @implementation YYAudioTool
    +(void)initialize
    {
        //音频会话
        AVAudioSession *session =[AVAudioSession sharedInstance];
        //设置绘画类型(播放类型,播放模式,会自动停止其他音乐的播放)
        [session setCategory:AVAudioSessionCategorySoloAmbient error:nil];
        //激活会话
        [session setActive:YES error:nil];
    }
    //.......

    三、创建歌词控件

    创建歌词控件
    歌词的格式说明:
    播放效果:
    毛玻璃效果的实现
    (1)让美工提供一张半透明的图片
    (2)利用一大堆的图形算法生成毛玻璃样式的UIImage对象
    这里使用一个第三方框架来生成毛玻璃效果
      毛玻璃:英文blur
      第三方框架:DRNRealTimeBlur
    具体实现:
      新建一个类,让其继承自,就能够实现毛玻璃效果。

    在xib中添加一个歌词控件。

    注意歌词控件的层级关系,退出和词图两个按钮应该在歌词控件的上面,这样才能够点击切换。

    把该控件和新建的类进行关联。

     

    添加约束,并清空其背景颜色。默认不显示,(设置隐藏)

     

    毛玻璃效果如下:

     

     

    简单的代码处理如下:

    YYLrcView.m文件

    //
    //  YYLrcView.m
    //  24-音频处理(音乐播放器5)
    //
    //  Created by apple on 14-8-15.
    //  Copyright (c) 2014年 yangyong. All rights reserved.
    //
    
    #import "YYLrcView.h"
    
    @interface YYLrcView ()<UITableViewDataSource,UITableViewDelegate>
    @property(nonatomic,strong)UITableView *tableView;
    @end
    @implementation YYLrcView
    
    - (id)initWithFrame:(CGRect)frame
    {
        self = [super initWithFrame:frame];
        if (self) {
            [self setup];
        }
        return self;
    }
    
    -(id)initWithCoder:(NSCoder *)aDecoder
    {
        self=[super initWithCoder:aDecoder];
        if (self) {
            [self setup];
        }
        return self;
    }
    
    -(void)setup
    {
        //添加表格控件
        UITableView *tableView=[[UITableView alloc]init];
        tableView.delegate=self;
        tableView.dataSource=self;
        [self addSubview:tableView];
        self.tableView=tableView;
    }
    
    #pragma mark-公共方法
    -(void)setLrcname:(NSString *)lrcname
    {
        _lrcname=[lrcname copy];
    }
    
    #pragma mark-数据源方法
    #warning TODO
    
    @end

    代码说明:

    注意:不要认为只有控制器才能作为tableView的数据源和代理。这也就是为什么代理和数据源属性的类型为id的原因,遵守其协议即可做其代理和数据源。

    -(id)initWithCoder:。从文件中读取一个对象的时候调用,为了程序的严谨性,建议在两个方法中调用初始化的代码。

    调用这个方法,说明对象是从文件中解析出来的。

    如果是通过代码allocinit创建的对象,那么调用-(id)initWithFrame:方法。

    说明:xib文件的本质是xml文件。

    四、主控制器的代码补充

    YYPlayingViewController.m文件

    //
    //  YYPlayingViewController.m
    //
    
    #import "YYPlayingViewController.h"
    #import "YYMusicTool.h"
    #import "YYMusicModel.h"
    #import "YYAudioTool.h"
    #import "YYLrcView.h"
    
    @interface YYPlayingViewController ()<AVAudioPlayerDelegate>
    - (IBAction)lyricOrPic:(UIButton *)sender;
    @property (weak, nonatomic) IBOutlet YYLrcView *lrcView;
    //显示拖拽进度
    @property (weak, nonatomic) IBOutlet UIButton *currentTimeView;
    //进度条
    @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;
    - (IBAction)previous;
    - (IBAction)playOrPause;
    - (IBAction)next;
    @property (weak, nonatomic) IBOutlet UIButton *playOrPauseButton;
    
    @end
    
    @implementation YYPlayingViewController
    
    -(void)viewDidLoad
    {
        [super viewDidLoad];
        
        //裁剪圆角
        self.currentTimeView.layer.cornerRadius=8;
        
    }
    #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 resetPlayingMusic];
        }
        
        //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)resetPlayingMusic
    {
        //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];
        
        //4.设置音乐播放按钮的状态
        self.playOrPauseButton.selected=NO;
    }
    //开始播放音乐数据
    -(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];
        self.player.delegate=self;
        
        //3.设置时长
        //self.player.duration;  播放器正在播放的音乐文件的时间长度
        self.durationLabel.text=[self strWithTime:self.player.duration];
        
        //4.添加定时器
        [self addCurrentTimeTimer];
        
        //5.设置音乐播放按钮的状态
        self.playOrPauseButton.selected=YES;
        
        //6.设置歌词
        self.lrcView.lrcname=self.playingMusic.lrcname;
    }
    
    /**
     *把时间长度-->时间字符串
     */
    -(NSString *)strWithTime:(NSTimeInterval)time
    {
        int minute=time / 60;
        int second=(int)time % 60;
        return [NSString stringWithFormat:@"%d:%d",minute,second];
    }
    
    #pragma mark-定时器控制
    /**
     *  添加一个定时器
     */
    -(void)addCurrentTimeTimer
    {
        //如果当前没有在播放,那么就直接返回
        if (self.player.isPlaying==NO) return;
        
        //在添加一个定时器之前,先把以前的定时器移除
        [self removeCurrentTime];
        
        //提前先调用一次进度更新,以保证定时器的工作时及时的
        [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
        CGFloat sliderMaxX=self.view.width-self.slider.width;
        self.slider.x+=t.x;
        //控制滑块的frame,不让其越界
        if(self.slider.x<0)
        {
            self.slider.x=0;
        }else if (self.slider.x>sliderMaxX)
        {
            self.slider.x=sliderMaxX;
        }
        //设置进度条的宽度
        self.progressView.width=self.slider.center.x;
        
        //3.设置时间值
        double progress=self.slider.x/sliderMaxX;
        //当前的时间值=音乐的时长*当前的进度值
        NSTimeInterval time=self.player.duration*progress;
        [self.slider setTitle:[self strWithTime:time] forState:UIControlStateNormal];
        
        //设置拖拽进度的X的值
        self.currentTimeView.x=self.slider.x;
        [self.currentTimeView setTitle:self.slider.currentTitle forState:UIControlStateNormal];
        
        //4.如果开始拖动,那么就停止定时器
        if (sender.state==UIGestureRecognizerStateBegan) {
            //停止定时器
            [self removeCurrentTime];
            
            //设置拖拽进度
            //显示
            self.currentTimeView.hidden=NO;
            self.currentTimeView.y=self.currentTimeView.superview.height-5-self.currentTimeView.height;
            
        }else if(sender.state==UIGestureRecognizerStateEnded)
        {
            //隐藏
            self.currentTimeView.hidden=YES;
            //设置播放器播放的时间
            self.player.currentTime=time;
    #warning 如果正在播放,才需要添加定时器
    //        if (self.player.isPlaying) {
            //开启定时器
            [self addCurrentTimeTimer];
    //        }
        }
    }
    
    //上一首
    - (IBAction)previous {
        //1.在开始播放之前,禁用一切的app点击事件
        UIWindow *window=[[UIApplication sharedApplication].windows lastObject];
        window.userInteractionEnabled=NO;
        
        //2.重置当前歌曲
        [self resetPlayingMusic];
        
        //3.获得上一首歌曲
        [YYMusicTool setPlayingMusic:[YYMusicTool previousMusic]];
        
        //4.播放上一首歌曲
        [self starPlayingMusic];
        
        //5.回复window的点击为可用
        window.userInteractionEnabled=YES;
    }
    //下一首
    - (IBAction)next {
        //1.在开始播放之前,禁用一切的app点击事件
        UIWindow *window=[[UIApplication sharedApplication].windows lastObject];
        window.userInteractionEnabled=NO;
        
        //2.重置当前歌曲
        [self resetPlayingMusic];
        
        //3.获得下一首歌曲
        [YYMusicTool setPlayingMusic:[YYMusicTool nextMusic]];
        
        //4.播放下一首歌曲
        [self starPlayingMusic];
        
        //5.回复window的点击为可用
        window.userInteractionEnabled=YES;
    }
    
    //继续或暂停播放
    - (IBAction)playOrPause {
        if (self.playOrPauseButton.isSelected) {//暂停
            self.playOrPauseButton.selected=NO;
            //暂停播放
            [YYAudioTool pauseMusic:self.playingMusic.filename];
            //停掉定时器
            [self removeCurrentTime];
        }else
        {
            self.playOrPauseButton.selected=YES;
            //继续播放
            [YYAudioTool playMusic:self.playingMusic.filename];
            //开启定时器
            [self addCurrentTimeTimer];
        }
    }
    
    #pragma mark-音乐播放器的代理
    //播放器播放完毕后就会调用该方法
    -(void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag
    {
        [self next];
    }
    //当播放器遇到中断的时候(如来电),调用该方法
    -(void)audioPlayerBeginInterruption:(AVAudioPlayer *)player
    {
        if (self.player.isPlaying) {
            //如果当前正在播放,那么就暂停
            [self playOrPause];
        }
    }
    //中断事件结束后调用下面的方法
    -(void)audioPlayerEndInterruption:(AVAudioPlayer *)player withOptions:(NSUInteger)flags
    {
        //可以什么都不做,让用户决定是继续播放还是暂停
    }
    - (IBAction)lyricOrPic:(UIButton *)sender {
        if (self.lrcView.hidden) {
            //显示歌词
            self.lrcView.hidden=NO;
            sender.selected=YES;
        }else
        {
            //隐藏歌词,显示歌手图片
            self.lrcView.hidden=YES;
            sender.selected=NO;
        }
    }
    @end

     

  • 相关阅读:
    HTTP长连接、短连接使用及测试
    递归分治算法之二维数组二分查找(Java版本)
    Java二维数组的概念和使用方法
    java二维数组遍历
    HashMap多线程并发问题分析
    Linux 移动或重命名文件/目录-mv 的10个实用例子
    CSS fixed 定位元素失效的问题
    关于 JavaScript 中的继承
    React 虚拟 DOM 的差异检测机制
    下拉框中选项的快速定位
  • 原文地址:https://www.cnblogs.com/yipingios/p/5566851.html
Copyright © 2020-2023  润新知