// // recordViewController.m // 双子星云手机 // // Created by xd h on 2025/3/28. // #import "recordViewController.h" #import "recordBottomView.h" #import "recordingView.h" #import #import "recordFileModel.h" #import "recordFileCell.h" #import "reNameRecordFileView.h" #import "ComontAlretViewController.h" #import "editTypeHeadView.h" #import "recordEditBottomView.h" #import "uploadFileRecordViewController.h" @interface recordViewController () @property (nonatomic, strong) UIButton *rightButton;//编辑 @property(nonatomic,strong) editTypeHeadView*curEditTypeHeadView; @property(nonatomic,strong) recordEditBottomView*curEditTypeBottomView; @property(nonatomic,strong) NSMutableArray* didSelectListArr; @property(nonatomic,assign) BOOL isEditType; @property (nonatomic, strong) UITableView *tableView; @property(nonatomic,strong)NSMutableArray *audioArr;//音频数据 @property(nonatomic,strong)recordBottomView *recordBottomV;//底部视图 @property(nonatomic,strong)recordingView *recordingV;//录音中 @property(nonatomic,strong)reNameRecordFileView * reNameRecordFileV; @property(nonatomic,strong)AVAudioPlayer * curAudioPlayer;//音频播放器 @property (strong, nonatomic) NSTimer *progressTimer; @property(nonatomic,strong) recordFileModel* curPlayerModel;//当前播放的音频数据 @end @implementation recordViewController - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. _audioArr = [NSMutableArray new]; _didSelectListArr = [NSMutableArray new]; [self drawAnyView]; [self getRecordDataFun]; } - (void)viewDidDisappear:(BOOL)animated { [super viewDidDisappear:animated]; if (_progressTimer) { [_progressTimer invalidate]; _progressTimer = nil; } } - (void)drawAnyView { [self.view setBackgroundColor:HWF5F7FAColor]; self.navBarBGView.hidden = NO; [self.navigationBar setHidden:YES]; [self.toolBar setHidden:YES]; [self.titleLabel setText:NSLocalizedString(@"mine_record_title",nil)]; self.navBarBGView.backgroundColor = [UIColor whiteColor]; //编辑 _rightButton = [[UIButton alloc] init]; [_rightButton setTitle:NSLocalizedString(@"edit_common",nil) forState:UIControlStateNormal]; [_rightButton setTitleColor:[UIColor hwColor:@"#01B7EA"] forState:UIControlStateNormal]; _rightButton.titleLabel.font = [UIFont systemFontOfSize:14.0]; _rightButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentRight; [_rightButton addTarget:self action:@selector(didClickEditFun) forControlEvents:UIControlEventTouchUpInside]; [self.navBarBGView addSubview:_rightButton]; [_rightButton mas_makeConstraints:^(MASConstraintMaker *make) { make.right.mas_equalTo(-15.f); make.width.mas_equalTo(40.f); make.centerY.equalTo(self.titleLabel.mas_centerY).offset(0.0); make.height.mas_equalTo(30); }]; _curEditTypeHeadView = [[editTypeHeadView alloc] init]; _curEditTypeHeadView.hidden = YES; [self.navBarBGView addSubview:_curEditTypeHeadView]; [_curEditTypeHeadView mas_makeConstraints:^(MASConstraintMaker *make) { make.left.mas_equalTo(0); make.right.mas_equalTo(0); make.bottom.mas_equalTo(0); make.height.mas_equalTo(NAVIHEIGHT - AdaptNaviHeight); }]; #pragma mark 编辑状态的 取消 和全选按钮 响应事件 KWeakSelf _curEditTypeHeadView.didClickButtonFun = ^(NSInteger tag) { if(tag==1){ [weakSelf userCancelEditTypeFun]; } }; _curEditTypeHeadView.didClickSelectAllFun = ^(UIButton * _Nonnull but) { [weakSelf didClickSelectAllButton:but]; }; _curEditTypeBottomView = [[recordEditBottomView alloc] init]; _curEditTypeBottomView.hidden = YES; [self.view addSubview:_curEditTypeBottomView]; [_curEditTypeBottomView mas_makeConstraints:^(MASConstraintMaker *make) { make.left.mas_equalTo(0); make.right.mas_equalTo(0); make.bottom.mas_equalTo(0); make.height.mas_equalTo(60 + AdaptTabHeight); }]; #pragma mark 编辑状态的 下载 删除 响应事件 _curEditTypeBottomView.didClickButtonFun = ^(NSInteger tag) { if(tag==1){ [weakSelf gotoUpLoadFileFun]; } else if(tag==3){ [weakSelf showDeleteAlearViewFun]; } }; //底部视图 _recordBottomV = [[recordBottomView alloc] init]; [self.view addSubview:_recordBottomV]; [_recordBottomV mas_makeConstraints:^(MASConstraintMaker *make) { make.left.mas_equalTo(0.f); make.right.mas_equalTo(0.f); make.bottom.mas_equalTo(0.f); make.height.mas_equalTo(100.f + AdaptTabHeight); }]; //KWeakSelf _recordBottomV.didClickRecordFun = ^{ [weakSelf didClickRecordFun]; }; [self.view addSubview:self.tableView]; [self.tableView mas_makeConstraints:^(MASConstraintMaker *make) { make.left.mas_equalTo(0); make.right.mas_equalTo(0); make.bottom.equalTo(self.recordBottomV.mas_top).offset(0.f); //make.bottom.mas_equalTo(0); make.top.equalTo(self.navBarBGView.mas_bottom).offset(10.f); }]; } #pragma mark - 懒加载 - (UITableView *)tableView{ if (!_tableView) { _tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_W, SCREEN_H - TABBARHEIGHT) style:UITableViewStylePlain]; _tableView.delegate = self; _tableView.dataSource = self; _tableView.showsVerticalScrollIndicator = NO; _tableView.showsHorizontalScrollIndicator = NO; // _tableView.contentInset = UIEdgeInsetsMake(-H_STATE_BAR, 0, 0, 0); [_tableView setSeparatorStyle:(UITableViewCellSeparatorStyleNone)]; [_tableView setSeparatorColor:[UIColor clearColor]]; [_tableView setBackgroundColor:[UIColor clearColor]]; [_tableView setTableFooterView:[UIView new]]; [_tableView setBounces:YES]; if (@available(iOS 15.0, *)) { _tableView.sectionHeaderTopPadding = 0; } //空数据引入第三方开源处理 _tableView.emptyDataSetSource = self; _tableView.emptyDataSetDelegate = self; // 下拉追加 // MJRefreshAutoNormalFooter *footer = [MJRefreshAutoNormalFooter footerWithRefreshingBlock:^{ // [self getMoreNetWorkData]; // }]; // // NSString *text = NSLocalizedString(@"NAS_bottom_tip",nil); // [footer setTitle:text forState:MJRefreshStateNoMoreData]; // _tableView.mj_footer = footer; } return _tableView; } #pragma mark - 列表委托 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{ if(!_audioArr){ return 0; } return _audioArr.count; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return 1; } - (recordFileCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ __block NSInteger row = indexPath.section; static NSString *identifier = @"recordFileCell"; recordFileCell * cell = [tableView dequeueReusableCellWithIdentifier:identifier]; cell.selectionStyle = UITableViewCellSelectionStyleNone; if (!cell){ cell = [[recordFileCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:identifier]; [cell setSelectionStyle:UITableViewCellSelectionStyleNone]; [cell setBackgroundColor:[UIColor clearColor]]; [cell setAccessoryType:(UITableViewCellAccessoryNone)]; } if(row < _audioArr.count){ recordFileModel* dataModel = _audioArr[row]; cell.curRecordFileModel = dataModel; KWeakSelf cell.didClickRecordButFun = ^(NSInteger index) { [weakSelf didClickCellFunBy:index withRow:row]; }; cell.didClickSwitch = ^(BOOL SwitchOn) { [weakSelf userCheckFilePreviewByRow:row]; }; } return cell; } - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{ NSInteger row = indexPath.section; if(row >=_audioArr.count){ return 0.0; } recordFileModel *model = _audioArr[row]; if (model.showAllType) { return 150; } return 65; } - (UIView*)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section { return [UIView new]; } - (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section{ return 12.0; } - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { if (_isEditType) { return; } NSInteger row = indexPath.section; if(row < _audioArr.count){ recordFileModel *model = _audioArr[row]; if(!model.showAllType){ model.showAllType = YES; [tableView reloadData]; } } } #pragma mark 空数据 - (UIImage *)imageForEmptyDataSet:(UIScrollView *)scrollView { NSString *imageName = @"common_no_data_pic"; return [UIImage imageNamed:imageName]; } - (NSAttributedString *)titleForEmptyDataSet:(UIScrollView *)scrollView { NSString *text = NSLocalizedString(@"record_no_data_tip",nil); NSDictionary *attributes = @{NSFontAttributeName: [UIFont systemFontOfSize:16.0f], NSForegroundColorAttributeName: HW999999Color}; return [[NSAttributedString alloc] initWithString:text attributes:attributes]; } //调整图片位置 - (CGFloat)verticalOffsetForEmptyDataSet:(UIScrollView *)scrollView { return -150; } #pragma mark 读取本地数据 - (void)getRecordDataFun { NSString *documentsDirectory = kSHPath_Record; NSFileManager *fileManager = [NSFileManager defaultManager]; NSError *error = nil; NSArray *fileList = [fileManager contentsOfDirectoryAtPath:documentsDirectory error:&error]; if (error) { HLog(@"Error reading contents of directory: %@", error.localizedDescription); } NSMutableArray *dataArr = [NSMutableArray new]; //BOOL isFirstType = YES; for (NSString *fileName in fileList) { NSString *filePath = [documentsDirectory stringByAppendingPathComponent:fileName]; // 获取文件属性 NSDictionary *fileAttributes = [fileManager attributesOfItemAtPath:filePath error:&error]; if (error) { NSLog(@"获取文件属性出错: %@ - %@", fileName, error.localizedDescription); error = nil; continue; } // 判断是否是目录 BOOL isDirectory = [fileAttributes[NSFileType] isEqualToString:NSFileTypeDirectory]; // 获取文件大小 unsigned long long fileSize = [fileAttributes[NSFileSize] unsignedLongLongValue]; recordFileModel *model = [recordFileModel new]; model.fileName = fileName; model.filePath = filePath; model.fileSize = fileSize; model.isDirectory = isDirectory; model.modificationDate = fileAttributes[NSFileModificationDate] ?: [NSDate date]; NSURL *fileUrl = [NSURL URLWithString:model.filePath]; NSTimeInterval time = [self getDurationOfAudioFile:fileUrl]; model.totalTime = (NSInteger)ceil(time); // 结果为 5; model.showAllType = NO; // if (isFirstType) { // model.showAllType = YES; // isFirstType = NO; // } // else{ // model.showAllType = NO; // } // 创建文件信息字典 // NSDictionary *fileInfo = @{ // @"name": fileName, // @"path": filePath, // @"size": @(fileSize), // @"isDirectory": @(isDirectory), // @"modificationDate": fileAttributes[NSFileModificationDate] ?: [NSDate date] // }; [dataArr addObject:model]; } // 假设你的对象有一个名为 dateProperty 的 NSDate 属性 NSArray *sortedArray = [dataArr sortedArrayUsingComparator:^NSComparisonResult(recordFileModel* obj1, recordFileModel* obj2) { return [obj2.modificationDate compare:obj1.modificationDate]; }]; [_audioArr removeAllObjects]; [_audioArr addObjectsFromArray:sortedArray]; recordFileModel *firstModel = _audioArr.firstObject; firstModel.showAllType = YES; } #pragma mark 获取录音文件的时长 - (NSTimeInterval)getDurationOfAudioFile:(NSURL *)fileURL { NSError *error; AVAudioPlayer *player = [[AVAudioPlayer alloc] initWithContentsOfURL:fileURL error:&error]; if (error) { HLog(@"Error: %@", error.localizedDescription); return 0; } return player.duration; } #pragma mark 点击了录音 - (void)didClickRecordFun { if(_recordingV){ return; } if(_curAudioPlayer){ [self audioPlayerPauseFun]; } //检测麦克风权限 AVAudioSessionRecordPermission permissionStatus = [[AVAudioSession sharedInstance] recordPermission]; // MicrophonePermissionStatus status; // switch (permissionStatus) { // case AVAudioSessionRecordPermissionUndetermined: // status = MicrophonePermissionStatusNotDetermined; // break; // case AVAudioSessionRecordPermissionDenied: // status = MicrophonePermissionStatusDenied; // break; // case AVAudioSessionRecordPermissionGranted: // status = MicrophonePermissionStatusGranted; // break; // } if (permissionStatus == AVAudioSessionRecordPermissionDenied) { NSString *tip = NSLocalizedString(@"mine_record_microphone_tip",nil); [[iToast makeText:tip] show]; return; } else if(permissionStatus == AVAudioSessionRecordPermissionUndetermined) { KWeakSelf [[AVAudioSession sharedInstance] requestRecordPermission:^(BOOL granted) { dispatch_async(dispatch_get_main_queue(), ^{ if (granted) { [weakSelf beginRecordFun]; } else { } }); }]; return; } [self beginRecordFun]; } #pragma mark 弹起录音功能 - (void)beginRecordFun { _recordingV = [[recordingView alloc] init]; [ksharedAppDelegate.window addSubview:_recordingV]; [_recordingV mas_makeConstraints:^(MASConstraintMaker *make) { make.left.mas_equalTo(0.f); make.right.mas_equalTo(0.f); make.bottom.mas_equalTo(0.f); make.top.mas_equalTo(0); }]; NSInteger index = _audioArr.count + 1; [_recordingV beginRecordFunWith:index]; KWeakSelf _recordingV.didClickRecordEndFun = ^{ [weakSelf deleteRecordingViewFun]; }; } #pragma mark 删除录音中界面 - (void)deleteRecordingViewFun { [_recordingV removeFromSuperview]; _recordingV = nil; [self getRecordDataFun]; [self.tableView reloadData]; } #pragma mark 点击cell里面的按钮事件 //index 1 编辑 2 删除 10 播放(100 暂停) 11 后退 12 前进 - (void)didClickCellFunBy:(NSInteger)index withRow:(NSInteger)row { switch (index) { case 1: [self didClickEditFunWithRow:row]; break; case 2: [self deleteFileByRow:row]; break; case 10: [self didClickPlayerByRow:row]; break; case 11: [self playerBackwardFun]; break; case 12: [self playerForwardFun]; break; case 100:// [self audioPlayerPauseFun]; break; default: break; } } #pragma mark 点击编辑 - (void)didClickEditFunWithRow:(NSInteger)row { recordFileModel *model = nil; if (_audioArr.count > row) { model = _audioArr[row]; } else{ return; } if (_reNameRecordFileV) { [_reNameRecordFileV removeFromSuperview]; } _reNameRecordFileV = [[reNameRecordFileView alloc] init]; [ksharedAppDelegate.window addSubview:_reNameRecordFileV]; _reNameRecordFileV.fileName = model.fileName; [_reNameRecordFileV mas_makeConstraints:^(MASConstraintMaker *make) { make.left.mas_equalTo(0.0); make.right.mas_equalTo(0.0); make.top.mas_equalTo(0.0); make.bottom.mas_equalTo(0.0); }]; KWeakSelf _reNameRecordFileV.didClickOkButtonFun = ^(NSString * _Nonnull newName) { [weakSelf checkRenameByNewName:newName withRow:row]; }; } #pragma mark 重命名逻辑 - (void)checkRenameByNewName:(NSString*)newName withRow:(NSInteger)row { [_reNameRecordFileV removeFromSuperview]; if (!newName || newName.length == 0) { NSString *tip = NSLocalizedString(@"record_reName_error_tip",nil); [[iToast makeText:tip] show]; return; } recordFileModel *model = nil; if (_audioArr.count > row) { model = _audioArr[row]; } else{ return; } BOOL isRepeatType = NO; for (int i=0; i<_audioArr.count; i++) { if (i != row) { recordFileModel *preModel = _audioArr[i]; if ([preModel.fileName isEqualToString:newName]) { isRepeatType = YES; break; } } } if (isRepeatType) { NSString *tip = NSLocalizedString(@"record_reName_error_repeat_tip",nil); [[iToast makeText:tip] show]; return; } //[_reNameRecordFileV removeFromSuperview]; // 获取文件管理器 NSFileManager *fileManager = [NSFileManager defaultManager]; // 原始文件路径 NSString *documentsPath = kSHPath_Record; NSString *oldFilePath = [documentsPath stringByAppendingPathComponent:model.fileName]; // 新文件路径 NSString *newFilePath = [documentsPath stringByAppendingPathComponent:newName]; NSError *error = nil; // 重命名/移动文件 BOOL success = [fileManager moveItemAtPath:oldFilePath toPath:newFilePath error:&error]; if (!success) { NSString *tip = NSLocalizedString(@"record_reName_error_title",nil); [[iToast makeText:tip] show]; } else { NSString *tip = NSLocalizedString(@"record_reName_ok_title",nil); [[iToast makeText:tip] show]; model.fileName = newName; [_tableView reloadData]; } } #pragma mark 文件删除弹框 - (void)showDeleteAlearViewFun { [self deleteFileByRow:-1]; } #pragma mark 文件删除 - (void)deleteFileByRow:(NSInteger)row { KWeakSelf /*弹窗提示重启*/ ComontAlretViewController *nextVC = [[ComontAlretViewController alloc] initWithTiTle:NSLocalizedString(@"delete_file_title_msg",nil) msg:NSLocalizedString(@"delete_file_tip_msg",nil) imageStr:@"" cancelTitle:NSLocalizedString(@"other_cancel",nil) okTitle:NSLocalizedString(@"delete_file_title_msg",nil) isOkBtnHighlight:YES didClickOk:^{ [weakSelf sureDeleteFileByRow:row]; } didClickCancel:^{ }]; nextVC.modalPresentationStyle = UIModalPresentationCustom; [self presentViewController:nextVC animated:YES completion:^{ nextVC.view.superview.backgroundColor = [UIColor clearColor]; }]; } #pragma mark 文件删除 - (void)sureDeleteFileByRow:(NSInteger)row { if (row == -1) {//删除编辑状态选中的旋转 [self deleteSelectFileFun]; return; } recordFileModel *model = nil; if (_audioArr.count > row) { model = _audioArr[row]; } else{ return; } NSFileManager *fileManager = [NSFileManager defaultManager]; NSString *filePath = model.filePath; // 获取要删除的文件路径 NSError *error = nil; BOOL success = [fileManager removeItemAtPath:filePath error:&error]; if (!success) { //NSLog(@"删除文件失败: %@", error.localizedDescription); [[iToast makeText:NSLocalizedString(@"record_deleteFile_fail",nil)] show]; } else { //NSLog(@"文件删除成功"); [[iToast makeText:NSLocalizedString(@"delete_file_suc_msg",nil)] show]; [_audioArr removeObject:model]; recordFileModel *firstModel = _audioArr.firstObject; firstModel.showAllType = YES; [_tableView reloadData]; } } #pragma mark 删除编辑状态选中的旋转 - (void)deleteSelectFileFun { NSFileManager *fileManager = [NSFileManager defaultManager]; for (recordFileModel*delModel in _didSelectListArr) { NSString *filePath = delModel.filePath; // 获取要删除的文件路径 NSError *error = nil; BOOL success = [fileManager removeItemAtPath:filePath error:&error]; if (!success) { //NSLog(@"删除文件失败: %@", error.localizedDescription); //[[iToast makeText:NSLocalizedString(@"record_deleteFile_fail",nil)] show]; } else { //NSLog(@"文件删除成功"); //[[iToast makeText:NSLocalizedString(@"delete_file_suc_msg",nil)] show]; [_audioArr removeObject:delModel]; } } // recordFileModel *firstModel = _audioArr.firstObject; // firstModel.showAllType = YES; [_tableView reloadData]; [[iToast makeText:NSLocalizedString(@"delete_file_suc_msg",nil)] show]; [_didSelectListArr removeAllObjects]; [self setEditTypeTitleFun]; } #pragma mark 点击了编辑按钮 - (void)didClickEditFun { _isEditType = YES; _curEditTypeHeadView.hidden = NO; _curEditTypeBottomView.hidden = NO; _recordBottomV.hidden = YES; [self setEditTypeTitleFun]; for (recordFileModel*model in _audioArr) { model.showAllType = NO; model.isEditType = YES; } [self.tableView mas_remakeConstraints:^(MASConstraintMaker *make) { make.left.mas_equalTo(0); make.right.mas_equalTo(0); make.bottom.mas_equalTo(_curEditTypeBottomView.mas_top); make.top.equalTo(self.navBarBGView.mas_bottom).offset(10.f); }]; [self.tableView reloadData]; } #pragma mark 用户取消编辑编辑 - (void)userCancelEditTypeFun { //数据还原 for (recordFileModel*model in _didSelectListArr) { model.isSelectType = NO; } [_didSelectListArr removeAllObjects]; for (recordFileModel*model in _audioArr) { model.isEditType = NO; } recordFileModel*firstModel = _audioArr.firstObject; firstModel.showAllType = YES; _isEditType = NO; [self.tableView reloadData]; _curEditTypeHeadView.hidden = YES; _curEditTypeBottomView.hidden = YES; _recordBottomV.hidden = NO; [self.tableView mas_remakeConstraints:^(MASConstraintMaker *make) { make.left.mas_equalTo(0); make.right.mas_equalTo(0); make.bottom.equalTo(self.recordBottomV.mas_top).offset(0.f); make.top.equalTo(self.navBarBGView.mas_bottom).offset(10.f);; }]; } - (void)didClickSelectAllButton:(UIButton*)button { //button.selected = !button.selected; [_didSelectListArr removeAllObjects]; for (recordFileModel* dataModel in _audioArr) { if(!button.selected){ dataModel.isSelectType = button.selected; } else{ [_didSelectListArr addObject:dataModel]; dataModel.isSelectType = button.selected; } } [self.tableView reloadData]; [self setEditTypeTitleFun]; } - (void)userCheckFilePreviewByRow:(NSInteger)row { if(row < _audioArr.count){ recordFileModel* dataModel = _audioArr[row]; if(dataModel.isSelectType){ [_didSelectListArr removeObject:dataModel]; } else{ [_didSelectListArr addObject:dataModel]; } dataModel.isSelectType = !dataModel.isSelectType; [self setEditTypeTitleFun]; } } #pragma mark 设置选中标题 - (void)setEditTypeTitleFun { [_curEditTypeHeadView setTitleLabetextByNumbers:_didSelectListArr.count]; if (_didSelectListArr.count > 0) { [_curEditTypeBottomView setButtonStateFunBy:YES]; } else{ [_curEditTypeBottomView setButtonStateFunBy:NO]; } } #pragma mark 处理上传 - (void)gotoUpLoadFileFun{ if (_didSelectListArr.count <= 0) { return; } uploadFileRecordViewController *vc = [uploadFileRecordViewController new]; [self.navigationController pushViewController:vc animated:YES]; vc.isUploadingType = YES; [vc gotoUploadFileByRecord:_didSelectListArr]; } #pragma mark 音频播放相关 - (void)didClickPlayerByRow:(NSInteger)row { if(row > _audioArr.count){ return; } recordFileModel* dataModel = _audioArr[row]; NSURL* fileURL = [NSURL URLWithString:dataModel.filePath]; _curPlayerModel = dataModel; for (recordFileModel*model in _audioArr) { model.isPlayingType = NO; } _curPlayerModel.isPlayingType = YES; if (_curAudioPlayer) { [_curAudioPlayer stop]; _curAudioPlayer = nil; } NSError *error; _curAudioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:fileURL error:&error]; _curAudioPlayer.delegate = self; _curAudioPlayer.currentTime = _curPlayerModel.curPlayerTime; [_curAudioPlayer play];//播放 [self startProgressTimer]; } #pragma mark 音频暂停播放 - (void)audioPlayerPauseFun { [_curAudioPlayer pause]; [self stopProgressTimer]; } #pragma mark 播放代理 - (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag { HLog(@"播放完成") [self stopProgressTimer]; _curPlayerModel.isPlayingType = NO; _curPlayerModel.curPlayerTime = 0;// _curPlayerModel.totalTime; [self.tableView reloadData]; } - (void)audioPlayerDecodeErrorDidOccur:(AVAudioPlayer *)player error:(NSError * __nullable)error { if (error) { HLog(@"解码失败") } } #pragma mark 播放进度相关 - (void)startProgressTimer { [self stopProgressTimer]; self.progressTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(updateProgress) userInfo:nil repeats:YES]; } - (void)stopProgressTimer { [self.progressTimer invalidate]; self.progressTimer = nil; } - (void)updateProgress { if (_curPlayerModel.totalTime > _curPlayerModel.curPlayerTime) { _curPlayerModel.curPlayerTime += 1; } [self.tableView reloadData]; } #pragma mark 向前15秒 - (void)playerForwardFun { _curPlayerModel.curPlayerTime += 15; if (_curPlayerModel.curPlayerTime > _curPlayerModel.totalTime) { _curPlayerModel.curPlayerTime = _curPlayerModel.totalTime -2; } _curAudioPlayer.currentTime = _curPlayerModel.curPlayerTime; [self.tableView reloadData]; } #pragma mark 向后15秒 - (void)playerBackwardFun { _curPlayerModel.curPlayerTime -= 15; if (_curPlayerModel.curPlayerTime < 0) { _curPlayerModel.curPlayerTime = 0; } _curAudioPlayer.currentTime = _curPlayerModel.curPlayerTime; [self.tableView reloadData]; } @end