Files
yinmeng-ios-store/yinmeng-ios/yinmeng-ios/Main/Home/View/SubView/MewPushExclusiveVoiceView.m
2024-01-20 11:02:21 +08:00

622 lines
21 KiB
Objective-C

//
// MewPushExclusiveVoiceView.m
// mew-ios
//
// Created by 触海 on 2023/11/10.
// 发布专属声音秀
#import "MewPushExclusiveVoiceView.h"
/// Tool
#import "MewMacro.h"
#import "UIImage+MewUtils.h"
#import "MewUtility.h"
#import "MewHUDTool.h"
/// Third
#import <Masonry/Masonry.h>
#import <AVFoundation/AVFoundation.h>
typedef enum : NSUInteger {
RecordVoiceState_Record_Start,//正在录制中
RecordVoiceState_Record_End,//录制结束
RecordVoiceState_Record_Normal //录制默认,未开始
} RecordVoiceState;
@interface MewPushExclusiveVoiceView() <UITextViewDelegate>
@property (nonatomic, strong) UIView *whiteBgView;
/// 标题文本
@property (nonatomic, strong) UILabel *titleLabel;
/// 关闭
@property (nonatomic, strong) UIButton *closeButton;
/// 声音操作
//长按
@property (nonatomic, strong) UIView *longTapView;
//长按文字
@property (nonatomic, strong) UILabel *longTapTitleLabel;
//长按图片
@property (nonatomic, strong) UIImageView *longTapImageView;
/// 录制过程的颜色view
@property (nonatomic, strong) UIView *longTapColorView;
//播放
@property (nonatomic, strong) UIButton *playVoiceButton;
//重播
@property (nonatomic, strong) UIButton *renewVoiceButton;
///介绍声音文本
@property (nonatomic, strong) UIView *textBgView;
@property (nonatomic, strong) UILabel *placeholdLabel;
@property (nonatomic, strong) UITextView *textView;
// 发布
@property (nonatomic, strong) UIButton *pushVoiceButton;
/// 录制声音的状态
@property (nonatomic, assign) RecordVoiceState recordVoiceState;
/// 是否正在播放声音
@property (nonatomic, assign) BOOL isPlayVoice;
/// 声音录制对象
@property (nonatomic, strong) AVAudioRecorder *audioRecorder;
///定时器
@property (nonatomic, strong) NSTimer *timer;
///倒计时
@property (nonatomic, assign) NSInteger countdown;
/// 音频文件名
@property (nonatomic, copy) NSString *fileName;
/// 本地录制的音频地址
@property (nonatomic, copy) NSString *totalFilePath;
///音频时长
@property (nonatomic, assign) NSInteger duration;
///播放器
@property (nonatomic, strong) AVAudioPlayer *player;
@end
@implementation MewPushExclusiveVoiceView
static MewPushExclusiveVoiceView *_exclusiveVoiceView = nil;
#pragma mark - Public Method
+ (instancetype)showPushExclusiveVoiceView {
if (!_exclusiveVoiceView) {
_exclusiveVoiceView = [[MewPushExclusiveVoiceView alloc] initWithFrame:UIScreen.mainScreen.bounds];
_exclusiveVoiceView.recordVoiceState = RecordVoiceState_Record_Normal;
}
if (!_exclusiveVoiceView.superview) {
[kAppKeyWindow addSubview:_exclusiveVoiceView];
}
return _exclusiveVoiceView;
}
+ (void)removeExclusiveViewFromSuperView {
if (_exclusiveVoiceView) {
[_exclusiveVoiceView removeFromSuperview];
_exclusiveVoiceView = nil;
}
}
#pragma mark - Init
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
self.backgroundColor = [MewAppColor mewGetAlphaColorOfTextWithHexString:0x000000 alpha:0.5];
[self mew_initView];
[self mew_initLayout];
}
return self;
}
#pragma mark - Action Event
- (void)closeButtonAction {
[MewPushExclusiveVoiceView removeExclusiveViewFromSuperView];
}
/// 长按录制
- (void)longRecordTapGesutre:(UITapGestureRecognizer *)longTap {
if (self.recordVoiceState == RecordVoiceState_Record_End || self.recordVoiceState == RecordVoiceState_Record_Start) return;
// 开始录制
[self startRecord];
}
/// 点击结束录音
- (void)tapRecordTapGesutre:(UITapGestureRecognizer *)tap {
// 没有在录音 || 录音结束,直接返回
if (self.recordVoiceState == RecordVoiceState_Record_Normal || self.recordVoiceState == RecordVoiceState_Record_End) {
return;
}
[self endRecord];
}
/// 播放录制声音
- (void)playWithRecordVoice:(UIButton *)sender {
if (self.recordVoiceState == RecordVoiceState_Record_Normal) {
[MewHUDTool showErrorWithMessage:@"请先录制声音"];
return;
}
if (self.recordVoiceState == RecordVoiceState_Record_Start) {
[MewHUDTool showErrorWithMessage:@"正在录制声音,请先结束录制"];
return;
}
sender.selected = !sender.selected;
[self playFilePathVoice];
}
/// 重新播放录制声音
- (void)renewPlayWithRecordVoice {
if (self.recordVoiceState == RecordVoiceState_Record_Normal) {
[MewHUDTool showErrorWithMessage:@"请先录制声音"];
return;
}
if (self.isPlayVoice) {
[MewHUDTool showErrorWithMessage:@"正在播放声音,请先结束播放"];
return;
}
[self cancelRecord];
[self startRecord];
}
/// 发布声音
- (void)pushWithRecordVoice {
if (self.totalFilePath.length == 0 || self.totalFilePath == nil) {
[MewHUDTool showErrorWithMessage:@"请先录制声音"];
return;
}
if (self.delegate) {
[self.delegate mewPushExclusiveVoice:self.totalFilePath voiceIntroString:self.textView.text dura:self.duration];
}
}
#pragma mark - UITextViewDelegate
- (void)textViewDidChange:(UITextView *)textView {
if (textView.text.length == 0 || [textView.text isEqualToString:@""]) {
self.placeholdLabel.hidden = NO;
} else {
self.placeholdLabel.hidden = YES;
}
}
#pragma mark - Private Method
/// 开始录制声音
- (void)startRecord {
[MewUtility checkMicPrivacy:^(BOOL succeed) {
if (!succeed) {
[MewHUDTool showErrorWithMessage:@"无麦克风权限,请到设置中打开麦克风权限"];
return;
}
[self initWithRecord];
}];
}
/// 暂停录制声音
- (void)endRecord {
self.recordVoiceState = RecordVoiceState_Record_End;
[self stopTimer];
[self.audioRecorder stop];
self.audioRecorder = nil;
///判断是否大于3s
AVAsset *audioAsset = [AVAsset assetWithURL:[NSURL fileURLWithPath:self.totalFilePath]];
CMTime audioDuration = audioAsset.duration;
float audioDurationSeconds = CMTimeGetSeconds(audioDuration);
if (audioDurationSeconds >= 3) {
self.duration = (NSInteger)audioDurationSeconds;
} else {
self.recordVoiceState = RecordVoiceState_Record_Normal;
[self deleteAudioFile];
[MewHUDTool showErrorWithMessage:@"录制的语音至少3s"];
}
}
/// 取消录制声音
- (void)cancelRecord {
[self stopTimer];
self.countdown = 0;
[self.audioRecorder stop];
[self deleteAudioFile];
}
/// 开始定时器
- (void)startTimer {
if (self.timer != nil) {
return;
}
// 最多15s
self.countdown = 15;
__block NSInteger count = 0;
__weak typeof(self) weakSelf = self;
self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0f repeats:YES block:^(NSTimer * _Nonnull timer) {
weakSelf.recordVoiceState = RecordVoiceState_Record_Start;
weakSelf.countdown--;
count++;
if (weakSelf.countdown > 0) {
NSLog(@"开始录制:%ld",weakSelf.countdown);
self.longTapTitleLabel.text = [NSString stringWithFormat:@"%ld's",count];
} else {
NSLog(@"结束录制");
[weakSelf endRecord];
}
}];
}
/// 结束定时器
- (void)stopTimer {
if (self.timer) {
[self.timer invalidate];
self.timer = nil;
}
}
- (void)playFilePathVoice {
if (self.isPlayVoice) {
[self.player stop];
self.player = nil;
self.isPlayVoice = NO;
return;
}
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback withOptions:AVAudioSessionCategoryOptionAllowBluetooth error:nil];
BOOL isFile = [[NSFileManager defaultManager] fileExistsAtPath:self.totalFilePath];
NSError *AVerror = NULL;
self.player = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:self.totalFilePath] error:&AVerror];
self.player.volume = 1;
self.player.numberOfLoops = -1;
[self.player prepareToPlay];
[self.player play];
self.isPlayVoice = YES;
}
///删除本地缓存文件
- (void)deleteAudioFile {
if ([[NSFileManager defaultManager] isDeletableFileAtPath:self.totalFilePath]) {
[[NSFileManager defaultManager] removeItemAtPath:self.totalFilePath error:NULL];
}
}
- (void)updateVoiceRecordColorView:(BOOL)isRecord isFinish:(BOOL)isFinish {
if (isFinish) {
self.longTapColorView.hidden = YES;
return;
}
self.longTapColorView.hidden = NO;
self.longTapColorView.backgroundColor = [MewAppColor mewGetColorOfTextWithHexString:isRecord ? 0xFF43B1 : 0x43F4FF];
}
/// 初始化录音对象
- (void)initWithRecord {
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
[audioSession setCategory:AVAudioSessionCategoryRecord error:nil];
//录音设置
NSMutableDictionary *recordSettings = [[NSMutableDictionary alloc] init];
//录音格式
[recordSettings setValue :[NSNumber numberWithInt:kAudioFormatLinearPCM] forKey: AVFormatIDKey];
//采样率
[recordSettings setValue :[NSNumber numberWithFloat:16000.0] forKey: AVSampleRateKey];
//通道数
[recordSettings setValue :[NSNumber numberWithInt:2] forKey: AVNumberOfChannelsKey];
//线性采样位数
[recordSettings setValue :[NSNumber numberWithInt:16] forKey: AVLinearPCMBitDepthKey];
//音频质量,采样质量
[recordSettings setValue:[NSNumber numberWithInt:AVAudioQualityMin] forKey:AVEncoderAudioQualityKey];
NSError *error = nil;
NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
[dateFormat setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
NSString *date = [dateFormat stringFromDate:[NSDate date]];
self.fileName = [NSString stringWithFormat:@"voiceShow_%@_%@.wav", [MewSaveBaseUserModel share].mewGetUserId, date];
NSFileManager *fileMgr = [[NSFileManager alloc] init];
//创建文件管理器
NSString *filePath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0] stringByAppendingPathComponent:@"voiceShow"];
self.totalFilePath = [filePath stringByAppendingPathComponent:self.fileName];
if (![fileMgr fileExistsAtPath:filePath]) {
//如果不存在,则说明是第一次运行这个程序,那么建立这个文件夹
[fileMgr createDirectoryAtPath:filePath withIntermediateDirectories:YES attributes:nil error:nil];
}
if (![fileMgr fileExistsAtPath:filePath]) { return; }
NSURL *fileUrl = [NSURL fileURLWithPath:self.totalFilePath];
self.audioRecorder = [[AVAudioRecorder alloc] initWithURL:fileUrl settings:recordSettings error:&error];
self.audioRecorder.meteringEnabled = YES;
[self.audioRecorder updateMeters];
NSLog(@"%f",[self.audioRecorder peakPowerForChannel:0]);
if(!self.audioRecorder) {
[MewHUDTool showErrorWithMessage:@"录制失败,请重试"];
return;
}
if(![self.audioRecorder prepareToRecord]) {
[MewHUDTool showErrorWithMessage:@"录制失败,请重试"];
return;
}
BOOL status = [self.audioRecorder record];
if (status) {
[self startTimer];
}
}
#pragma mark - Init View
- (void)mew_initView {
[self addSubview:self.whiteBgView];
[self.whiteBgView addSubview:self.titleLabel];
[self.whiteBgView addSubview:self.closeButton];
/// 声音操作
[self.whiteBgView addSubview:self.longTapView];
[self.longTapView addSubview:self.longTapTitleLabel];
[self.longTapView addSubview:self.longTapImageView];
[self.longTapView addSubview:self.longTapColorView];
[self.whiteBgView addSubview:self.playVoiceButton];
[self.whiteBgView addSubview:self.renewVoiceButton];
///介绍声音文本
[self.whiteBgView addSubview:self.textBgView];
[self.textBgView addSubview:self.placeholdLabel];
[self.whiteBgView addSubview:self.textView];
[self.whiteBgView addSubview:self.pushVoiceButton];
}
- (void)mew_initLayout {
[self.whiteBgView mas_makeConstraints:^(MASConstraintMaker *make) {
make.center.equalTo(self);
make.width.mas_equalTo(KMewGetScreenWidth - 56);
}];
[self.titleLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.whiteBgView).offset(10);
make.centerX.equalTo(self.whiteBgView);
}];
[self.closeButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.right.equalTo(self.whiteBgView).offset(-10);
make.width.height.mas_equalTo(24);
make.centerY.equalTo(self.titleLabel);
}];
/// 声音操作
[self.longTapView mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerX.equalTo(self.whiteBgView);
make.width.height.mas_equalTo(68);
make.top.equalTo(self.titleLabel.mas_bottom).offset(16);
}];
[self.longTapTitleLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerX.equalTo(self.longTapView);
make.bottom.equalTo(self.longTapView).offset(-9);
}];
[self.longTapImageView mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerX.equalTo(self.longTapView);
make.bottom.equalTo(self.longTapTitleLabel.mas_top);
}];
[self.longTapColorView mas_makeConstraints:^(MASConstraintMaker *make) {
make.bottom.right.equalTo(self.longTapImageView);
make.width.height.mas_equalTo(6);
}];
[self.renewVoiceButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.longTapView.mas_right).offset(26);
make.centerY.equalTo(self.longTapView);
}];
[self.playVoiceButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.renewVoiceButton);
make.right.equalTo(self.longTapView.mas_left).offset(-26.0);
}];
///介绍声音文本
[self.textBgView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.whiteBgView).offset(28);
make.right.equalTo(self.whiteBgView).offset(-20);
make.height.mas_equalTo(96);
make.top.equalTo(self.longTapView.mas_bottom).offset(16.0);
}];
[self.placeholdLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.left.equalTo(self.textView);
}];
[self.textView mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.left.equalTo(self.textBgView).offset(5.0);
make.right.bottom.equalTo(self.textBgView).offset(-5.0);
}];
[self.pushVoiceButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.textBgView.mas_bottom).offset(20.0);
make.left.equalTo(self.whiteBgView).offset(28);
make.right.equalTo(self.whiteBgView).offset(-28);
make.height.mas_equalTo(46);
make.bottom.equalTo(self.whiteBgView).offset(-24.0);
}];
}
#pragma mark - Get
- (void)setRecordVoiceState:(RecordVoiceState)recordVoiceState {
_recordVoiceState = recordVoiceState;
if (_recordVoiceState == RecordVoiceState_Record_Normal) {
self.longTapTitleLabel.text = @"长按录制";
}
if (_recordVoiceState == RecordVoiceState_Record_End) {
self.longTapTitleLabel.text = @"录制完成";
}
[self updateVoiceRecordColorView:recordVoiceState == RecordVoiceState_Record_Start isFinish:recordVoiceState == RecordVoiceState_Record_End];
self.longTapImageView.image = [UIImage imageNamed: recordVoiceState == RecordVoiceState_Record_End ? @"mew_home_voice_record_end" : @"mew_home_voice_record_start"];
}
#pragma mark - Get
- (UIView *)whiteBgView {
if (!_whiteBgView) {
_whiteBgView = [[UIView alloc] init];
_whiteBgView.backgroundColor = [MewAppColor mewGetColorOfTextWithHexString:0x525566];;
_whiteBgView.layer.cornerRadius = 15.0;
_whiteBgView.layer.masksToBounds = YES;
}
return _whiteBgView;
}
- (UILabel *)titleLabel {
if (!_titleLabel) {
_titleLabel = [[UILabel alloc] init];
_titleLabel.text = @"发布专属声音秀";
_titleLabel.font = kMewSetFontMedium(16);
_titleLabel.textColor = UIColor.whiteColor;
}
return _titleLabel;
}
- (UIButton *)closeButton {
if (!_closeButton) {
_closeButton = [[UIButton alloc] init];
[_closeButton setImage:[UIImage imageNamed:@"mew_home_change_voice_close"] forState:UIControlStateNormal];
[_closeButton addTarget:self action:@selector(closeButtonAction) forControlEvents:UIControlEventTouchUpInside];
}
return _closeButton;
}
/// 声音操作
- (UIView *)longTapView {
if (!_longTapView) {
_longTapView = [[UIView alloc] init];
_longTapView.backgroundColor = [MewAppColor mewGetColorOfTextWithHexString:0x9552FF];
_longTapView.layer.cornerRadius = 24.0;
_longTapView.layer.masksToBounds = YES;
//长按
UILongPressGestureRecognizer *longTap = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longRecordTapGesutre:)];
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapRecordTapGesutre:)];
[_longTapView addGestureRecognizer:tap];
[_longTapView addGestureRecognizer:longTap];
}
return _longTapView;
}
- (UILabel *)longTapTitleLabel {
if (!_longTapTitleLabel) {
_longTapTitleLabel = [[UILabel alloc] init];
_longTapTitleLabel.text = @"长按录制";
_longTapTitleLabel.font = kMewSetFontRegular(12);
_longTapTitleLabel.textColor = UIColor.whiteColor;
}
return _longTapTitleLabel;
}
- (UIImageView *)longTapImageView {
if (!_longTapImageView) {
_longTapImageView = [[UIImageView alloc] init];
_longTapImageView.image = [UIImage imageNamed:@"mew_home_voice_record_start"];
}
return _longTapImageView;
}
- (UIView *)longTapColorView {
if (!_longTapColorView) {
_longTapColorView = [[UIView alloc] init];
_longTapColorView.backgroundColor = [MewAppColor mewGetColorOfTextWithHexString:0x43F4FF];
_longTapColorView.layer.cornerRadius = 6.0/2.0;
_longTapColorView.layer.masksToBounds = YES;
}
return _longTapColorView;
}
- (UIButton *)playVoiceButton {
if (!_playVoiceButton) {
_playVoiceButton = [[UIButton alloc] init];
[_playVoiceButton setImage:[UIImage imageNamed:@"mew_home_voice_record_stop"] forState:UIControlStateSelected];
[_playVoiceButton setImage:[UIImage imageNamed:@"mew_home_voice_record_play"] forState:UIControlStateNormal];
[_playVoiceButton addTarget:self action:@selector(playWithRecordVoice:) forControlEvents:UIControlEventTouchUpInside];
_playVoiceButton.selected = NO;
}
return _playVoiceButton;
}
- (UIButton *)renewVoiceButton {
if (!_renewVoiceButton) {
_renewVoiceButton = [[UIButton alloc] init];
[_renewVoiceButton setImage:[UIImage imageNamed:@"mew_home_voice_record_restart"] forState:UIControlStateNormal];
[_renewVoiceButton addTarget:self action:@selector(renewPlayWithRecordVoice) forControlEvents:UIControlEventTouchUpInside];
}
return _renewVoiceButton;
}
///介绍声音文本
- (UIView *)textBgView {
if (!_textBgView) {
_textBgView = [[UIView alloc] init];
_textBgView.backgroundColor = [MewAppColor mewGetColorOfTextWithHexString:0xDCDDE0];
_textBgView.layer.cornerRadius = 11.0;
_textBgView.layer.masksToBounds = YES;
}
return _textBgView;
}
- (UITextView *)textView {
if (!_textView) {
_textView = [[UITextView alloc] init];
_textView.delegate = self;
_textView.font = kMewSetFontRegular(13);
_textView.textColor = [MewAppColor mewGetColorOfTextWithHexString:0x7D8499];
_textView.backgroundColor = UIColor.clearColor;
}
return _textView;
}
- (UILabel *)placeholdLabel {
if (!_placeholdLabel) {
_placeholdLabel = [[UILabel alloc] init];
_placeholdLabel.text = @"说点什么...";
_placeholdLabel.textColor = [MewAppColor mewGetColorOfTextWithHexString:0x7D8499];
_placeholdLabel.font = kMewSetFontRegular(13);
}
return _placeholdLabel;
}
- (UIButton *)pushVoiceButton {
if (!_pushVoiceButton) {
_pushVoiceButton = [[UIButton alloc] init];
[_pushVoiceButton setTitle:@"发布" forState:UIControlStateNormal];
[_pushVoiceButton setTitleColor:UIColor.whiteColor forState:UIControlStateNormal];
_pushVoiceButton.titleLabel.font = kMewSetFontSemibold(16);
_pushVoiceButton.layer.cornerRadius = 23.0;
_pushVoiceButton.layer.masksToBounds = YES;
UIImage *image = [UIImage mew_gradientColorImageFromColors:@[[MewAppColor mewGetColorOfTextWithHexString:0xFF60FD], [MewAppColor mewGetColorOfTextWithHexString:0x8974FF],[MewAppColor mewGetColorOfTextWithHexString:0x69EBFF]] gradientType:MewGradientTypeLeftToRight imgSize:CGSizeMake(KMewGetScreenWidth - 4 * 28, 46)];
_pushVoiceButton.backgroundColor = [UIColor colorWithPatternImage:image];
[_pushVoiceButton addTarget:self action:@selector(pushWithRecordVoice) forControlEvents:UIControlEventTouchUpInside];
}
return _pushVoiceButton;
}
@end