ios音频播放以及时间显示

本文介绍了一种在iOS应用中实现音频播放的方法,并详细讲解了如何通过自定义动画增强用户体验。此外,还提供了播放界面布局及手势交互的具体实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

主要实现的功能为:音频播放,音频播放时自定义动画以及音频时间显示

一、头文件和代理添加

在.h文件中添加

#import <AVFoundation/AVFoundation.h>
<AVAudioPlayerDelegate,infoRecordViewDelegate//自定义播放界面的代理>

二、在.h文件中声明

@property (nonatomic,strong) playRecordView *playRecView;//录音

@property (nonatomic,strong) UILabel *title;

@property (nonatomic,strong) UIImageView *recordPhoto;

@property (nonatomic,strong) UILabel *lbltime;

@property (nonatomic,strong) UITapGestureRecognizer *tapPlayGesture;//点击播放手势
@property (nonatomic,strong) UITapGestureRecognizer *tapCloseGesture;//点击添加关闭手势
@property (nonatomic,strong) UITapGestureRecognizer *tapShowGesture;//点击添加展示手势

@property (nonatomic,assign) NSInteger countNum;//录音计时(秒)
@property (nonatomic,strong) NSTimer *playTimer;//控制播放时长显示更新
@property (nonatomic,strong) NSString *timeString;//播放时间

三、播放界面布局

#pragma mark - playRecView界面布局
- (UILabel *)titleInit
{
    if (!_title) {
        self.title = [[UILabel alloc]init];
        self.title.text = @"录音";
        [self addSubview:self.title];

        [self.title mas_makeConstraints:^(MASConstraintMaker *make) {
            make.left.mas_equalTo(self).offset(0);
            make.centerY.mas_equalTo(self.centerY).offset(0);
            make.width.mas_equalTo(60);
        }];
    }
    return self.title;
}

- (UIImageView *)recordImageViewInit
{
    if (!_recordPhoto) {
//        self.recordPhoto = [[UIImageView alloc]init];
//        self.recordPhoto.image = [UIImage imageNamed:@"playRecord0.png"];

        //自定义动画
        self.recordPhoto = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"playRecord0"]];
//        self.recordPhoto.size = CGSizeMake(SCREEN_WIDTH * 0.9 - 10 - 60,SCREEN_HEIGHT * 0.06);


        NSArray *picArray = @[[UIImage imageNamed:@"playRecord1"],
                              [UIImage imageNamed:@"playRecord2"],
                              [UIImage imageNamed:@"playRecord3"],];


        [self.recordPhoto setAnimationImages:picArray];
        //    self.recordPhoto.contentMode = UIViewContentModeScaleAspectFit;
        [self.recordPhoto setAnimationDuration:1.5];
        [self.recordPhoto setAnimationRepeatCount:0];

        [self addSubview:self.recordPhoto];


        [self.recordPhoto mas_makeConstraints:^(MASConstraintMaker *make) {
            make.left.mas_equalTo(self.title.mas_right).offset(0);
            make.centerY.mas_equalTo(self.centerY).offset(0);
            make.width.mas_equalTo(SCREEN_WIDTH * 0.9 - 10 - 60);
            make.height.mas_equalTo(SCREEN_HEIGHT * 0.06);
        }];
    }
    return self.recordPhoto;
}

- (UILabel *)lbltimeInit
{
    if (!_lbltime) {
        self.lbltime = [[UILabel alloc]init];
        self.lbltime.textColor = MF_ColorFromRGBA2(0x333333, 1);
        self.lbltime.text = @"00:00";
        [self.lbltime setHidden:YES];

        [self addSubview:self.lbltime];
        [self.lbltime mas_makeConstraints:^(MASConstraintMaker *make) {
            make.right.mas_equalTo(self.recordPhoto.mas_right).offset(0);
            make.centerY.mas_equalTo(self.recordPhoto.centerY).offset(0);
            make.size.mas_equalTo(CGSizeMake(60, 30));
        }];
    }
    return _lbltime;
}

四、播放界面

在.m文件中添加

#define kSandboxPathStr [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject]
- (void)viewWillDisappear:(BOOL)animated
{
    [self stopAllMusic];
}
- (void)viewDidDisappear:(BOOL)animated
{
    //停止播放动画
    [self stopPlayAnimation];
}
#pragma mark - 数据初始化
- (void)setData
{
            _tapPlayGesture = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(playRecordGestureClick:)];
        self.playRecView = [[playRecordView alloc]init];
        self.playRecView.recordPhoto.userInteractionEnabled = YES;
        self.playRecView.recordPhoto.tag = 20000 + i;
        self.playRecView.tag = 20000 + i;
        [[self.playRecView.recordPhoto viewWithTag:20000 + i] addGestureRecognizer:_tapPlayGesture];



        self.playRecView.frame = CGRectMake(SCREEN_WIDTH * 0.05, 60 + SCREEN_HEIGHT * 0.08 * i, SCREEN_WIDTH * 0.9 - 10, SCREEN_HEIGHT * 0.08);
        [self.recordBackView addSubview:self.playRecView];
}
//播放手势触发
- (void)playRecordGestureClick:(UITapGestureRecognizer *)playGesture
{
    if(playImageView && playImageView.isAnimating)
    {

        [_recordView stopAllMusic];
        [playImageView stopAnimating];
        for (playRecordView *playRecView in _recordBackView.subviews) {
            if (playRecView.tag == playImageView.tag) {
                [playRecView.lbltime setHidden:YES];

                playRecView.lbltime.text = @"00:00";
            }
        }
        [self.playTimer invalidate];

    }else{
        playImageView = (UIImageView*)playGesture.view;
        NSInteger index = playImageView.tag - 20000;

        [playImageView startAnimating];

        [_recordView playRecord:[self.recordArray objectAtIndex:index]];

        //获取总时间
        [self.playTimer fire];

    }

    NSLog(@"%ld",(long)index);


}

//停止播放动画代理
- (void)stopPlayAnimation
{
    if(playImageView && playImageView.isAnimating)
    {
        for (playRecordView *playRecView in _recordBackView.subviews) {
            if (playRecView.tag == playImageView.tag) {
                [playRecView.lbltime setHidden:YES];
                playRecView.lbltime.text = @"00:00";
            }
        }
        [self.playTimer invalidate];

        [playImageView stopAnimating];
    }
}
-(void)sendTotalTime:(NSTimeInterval)totalTime currentTime:(NSTimeInterval)currentTime
{
    self.countNum = 0;
    NSTimeInterval timeInterval =1 ;
    //    1s
    self.playTimer = [NSTimer scheduledTimerWithTimeInterval:timeInterval  target:self selector:@selector(updatePlayTimerValue)  userInfo:nil  repeats:YES];

    tduration = totalTime;

}

-(void)updatePlayTimerValue
{
    self.countNum += 1;
    NSUInteger seconds = (NSUInteger)round(tduration);
    _timeString = [NSString stringWithFormat:@"00:%02lu",seconds % 60 - self.countNum];

    for (playRecordView *playRecView in _recordBackView.subviews) {
        if (playRecView.tag == playImageView.tag) {
            [playRecView.lbltime setHidden:NO];
            if (self.countNum >= (seconds % 60)) {
                playRecView.lbltime.text = @"00:00";
            }else{
                playRecView.lbltime.text = _timeString;
            }
        }
    }

}

五、recordView(播放方法:核心)

.h文件

@protocol infoRecordViewDelegate<NSObject>
@optional
//获取录音数据
-(void)getRecordData:(NSString *)path type:(NSString *)type fileName:(NSString *)fileName;//获取数据
//停止播放动画
- (void)stopPlayAnimation;

//发送时间
- (void)sendTotalTime:(NSTimeInterval)totalTime currentTime:(NSTimeInterval)currentTime;

@end

@interface infoRecordView : UIView<AVAudioPlayerDelegate>

@property (nonatomic,strong) AVAudioPlayer *audioPlayer;//音频播放器
@property (nonatomic,assign) NSInteger countNum;//录音计时(秒)
@property (nonatomic,strong) NSTimer *playTimer;//控制播放时长显示更新
@property (nonatomic,strong) NSString *timeString;//播放时间
@property (nonatomic,strong) UIButton *closeBtn; //关闭按钮
@property (nonatomic,strong) UIView *playBackView;//播放动画背景

@property (nonatomic,copy) NSString *cafPathStr;

@property (nonatomic,weak) id<infoRecordViewDelegate>delegate;

@property (nonatomic,strong) UIImageView *playAniImageView;//播放动画

- (void)playRecord:(NSString *)path view:(UIView *)view;

- (void)playRecord:(NSString *)path;

- (void)stopAllMusic;//停止播放

.m文件

#pragma mark - 播放
- (void)playRecord:(NSString *)path view:(UIView *)view
{
    [self stopAllMusic];

    AVAudioSession *audioSession=[AVAudioSession sharedInstance];
    [audioSession setCategory:AVAudioSessionCategoryPlayback error:nil];  //此处需要恢复设置回放标志,否则会导致其它播放声音也会变小

    NSString *newPath = [path substringFromIndex:1];//路径第一位多了个/

    [self playMusicWithUrl:[NSURL URLWithString:newPath]];
}

//查看历史使用
- (void)playRecord:(NSString *)path
{
    [self stopAllMusic];

    AVAudioSession *audioSession=[AVAudioSession sharedInstance];
    [audioSession setCategory:AVAudioSessionCategoryPlayback error:nil];  //此处需要恢复设置回放标志,否则会导致其它播放声音也会变小

    NSString *newPath = [path substringFromIndex:1];//路径第一位多了个/

    [self playMusicWithUrl:[NSURL URLWithString:newPath]];

}

- (void)stopPlayRecord
{
    [self stopMusicWithUrl:[NSURL URLWithString:self.cafPathStr]];
}
-(void)deleteOldRecordFile{
    NSFileManager* fileManager=[NSFileManager defaultManager];

    BOOL blHave=[[NSFileManager defaultManager] fileExistsAtPath:self.cafPathStr];
    if (!blHave) {
//        NSLog(@"不存在");
        return ;
    }else {
//        NSLog(@"存在");
        BOOL blDele= [fileManager removeItemAtPath:self.cafPathStr error:nil];
        if (blDele) {
//            NSLog(@"删除成功");
        }else {
//            NSLog(@"删除失败");
        }
    }
}


-(void)deleteOldRecordFileAtPath:(NSString *)pathStr{
    NSFileManager* fileManager=[NSFileManager defaultManager];

    BOOL blHave=[[NSFileManager defaultManager] fileExistsAtPath:pathStr];
    if (!blHave) {
//        NSLog(@"不存在");
        return ;
    }else {
//        NSLog(@"存在");
        BOOL blDele= [fileManager removeItemAtPath:self.cafPathStr error:nil];
        if (blDele) {
//            NSLog(@"删除成功");
        }else {
//            NSLog(@"删除失败");
        }
    }
}

-(void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag
{
//    NSLog(@"delegate--播放完毕----------------------");

    //停止播放动画代理
    [self.delegate stopPlayAnimation];

    [HUD hide:YES];
}

#pragma mark - AudioPlayer方法

/**
 *播放音乐文件
 */
- (BOOL)playMusicWithUrl:(NSURL *)fileUrl
{
    //其他播放器停止播放
    [self stopAllMusic];

    if (!fileUrl) return NO;

    AVAudioSession *session=[AVAudioSession sharedInstance];
    [session setCategory:AVAudioSessionCategoryPlayback error:nil];  //此处需要恢复设置回放标志,否则会导致其它播放声音也会变小
    [session setActive:YES error:nil];

    NSError *error;

    _audioPlayer = [self musices][fileUrl];

#warning 不能加入全局异常断点,不然会卡在这里
    if (!_audioPlayer) {
        //2.2创建播放器
        _audioPlayer=[[AVAudioPlayer alloc]initWithContentsOfURL:fileUrl error:&error];

    }

    _audioPlayer.delegate = self;

    if (![_audioPlayer prepareToPlay]){
        NSLog(@"缓冲失败--");
        //        [self myToast:@"播放器缓冲失败"];
        return NO;
    }

    if (![_audioPlayer isPlaying]){
        //串行同步
        dispatch_queue_t queue = dispatch_queue_create("test.queue", DISPATCH_QUEUE_SERIAL);

        dispatch_sync(queue, ^{
            [self.delegate sendTotalTime:_audioPlayer.duration currentTime:_audioPlayer.currentTime];
        });
        dispatch_sync(queue, ^{
            //播放
            [_audioPlayer play];
        });

    }
    //2.4存入字典
    [self musices][fileUrl]=_audioPlayer;

//    NSLog(@"musices:%@ musices",self.musices);
      return YES;//正在播放,那么就返回YES
}

/**
 *停止播放音乐文件
 */
- (void)stopMusicWithUrl:(NSURL *)fileUrl{
    if (!fileUrl) return;//如果没有传入文件名,那么就直接返回

    //1.取出对应的播放器
    AVAudioPlayer *player=[self musices][fileUrl];

    //2.停止
    if ([player isPlaying]) {
        [player stop];
//        NSLog(@"播放结束:%@--------",fileUrl);
    }

    if ([[self musices].allKeys containsObject:fileUrl]) {

        [[self musices] removeObjectForKey:fileUrl];
    }
}

//停止所有正在播放的音频
- (void)stopAllMusic
{

    if ([self musices].allKeys.count > 0) {
        for ( NSString *playID in [self musices].allKeys) {

            AVAudioPlayer *player=[self musices][playID];
            [player stop];            
        }
    }

    if(HUD){
        [HUD hide:YES];
    }


}

- (NSMutableDictionary *)musices
{
    if (_musices==nil) {
        _musices=[NSMutableDictionary dictionary];
    }
    return _musices;
}

PS:ios录音功能实现http://blog.youkuaiyun.com/fantasy_jun/article/details/77894709

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值