mirror of
https://github.com/TencentCloud/TIMSDK.git
synced 2026-10-21 08:46:21 +08:00
527 lines
22 KiB
Objective-C
527 lines
22 KiB
Objective-C
//
|
||
// TUIInputBar.m
|
||
// UIKit
|
||
//
|
||
// Created by kennethmiao on 2018/9/18.
|
||
// Copyright © 2018年 Tencent. All rights reserved.
|
||
//
|
||
|
||
#import "TUIInputBar.h"
|
||
#import "TUIRecordView.h"
|
||
#import "TUIDefine.h"
|
||
#import "TUITool.h"
|
||
#import "TUIDefine.h"
|
||
#import <AVFoundation/AVFoundation.h>
|
||
#import "ReactiveObjC/ReactiveObjC.h"
|
||
#import "UIView+TUILayout.h"
|
||
#import "TUIDarkModel.h"
|
||
#import "TUIGlobalization.h"
|
||
#import "TUIThemeManager.h"
|
||
|
||
@interface TUIInputBar() <UITextViewDelegate, AVAudioRecorderDelegate>
|
||
@property (nonatomic, strong) TUIRecordView *record;
|
||
@property (nonatomic, strong) NSDate *recordStartTime;
|
||
@property (nonatomic, strong) AVAudioRecorder *recorder;
|
||
@property (nonatomic, strong) NSTimer *recordTimer;
|
||
@end
|
||
|
||
@implementation TUIInputBar
|
||
|
||
- (id)initWithFrame:(CGRect)frame
|
||
{
|
||
self = [super initWithFrame:frame];
|
||
if(self){
|
||
[self setupViews];
|
||
[self defaultLayout];
|
||
}
|
||
return self;
|
||
}
|
||
|
||
- (void)setupViews
|
||
{
|
||
self.backgroundColor = TUIChatDynamicColor(@"chat_input_controller_bg_color", @"#EBF0F6");
|
||
|
||
_lineView = [[UIView alloc] init];
|
||
_lineView.backgroundColor = TUICoreDynamicColor(@"separtor_color", @"#FFFFFF");
|
||
|
||
_micButton = [[UIButton alloc] init];
|
||
[_micButton addTarget:self action:@selector(clickVoiceBtn:) forControlEvents:UIControlEventTouchUpInside];
|
||
[_micButton setImage:[UIImage d_imageNamed:@"ToolViewInputVoice" bundle:TUIChatBundle] forState:UIControlStateNormal];
|
||
[_micButton setImage:[UIImage d_imageNamed:@"ToolViewInputVoiceHL" bundle:TUIChatBundle] forState:UIControlStateHighlighted];
|
||
[self addSubview:_micButton];
|
||
|
||
_faceButton = [[UIButton alloc] init];
|
||
[_faceButton addTarget:self action:@selector(clickFaceBtn:) forControlEvents:UIControlEventTouchUpInside];
|
||
[_faceButton setImage:[UIImage d_imageNamed:@"ToolViewEmotion" bundle:TUIChatBundle] forState:UIControlStateNormal];
|
||
[_faceButton setImage:[UIImage d_imageNamed:@"ToolViewEmotionHL" bundle:TUIChatBundle] forState:UIControlStateHighlighted];
|
||
[self addSubview:_faceButton];
|
||
|
||
_keyboardButton = [[UIButton alloc] init];
|
||
[_keyboardButton addTarget:self action:@selector(clickKeyboardBtn:) forControlEvents:UIControlEventTouchUpInside];
|
||
[_keyboardButton setImage:[UIImage d_imageNamed:@"ToolViewKeyboard" bundle:TUIChatBundle] forState:UIControlStateNormal];
|
||
[_keyboardButton setImage:[UIImage d_imageNamed:@"ToolViewKeyboardHL" bundle:TUIChatBundle] forState:UIControlStateHighlighted];
|
||
_keyboardButton.hidden = YES;
|
||
[self addSubview:_keyboardButton];
|
||
|
||
_moreButton = [[UIButton alloc] init];
|
||
[_moreButton addTarget:self action:@selector(clickMoreBtn:) forControlEvents:UIControlEventTouchUpInside];
|
||
[_moreButton setImage:[UIImage d_imageNamed:@"TypeSelectorBtn_Black" bundle:TUIChatBundle] forState:UIControlStateNormal];
|
||
[_moreButton setImage:[UIImage d_imageNamed:@"TypeSelectorBtnHL_Black" bundle:TUIChatBundle] forState:UIControlStateHighlighted];
|
||
[self addSubview:_moreButton];
|
||
|
||
_recordButton = [[UIButton alloc] init];
|
||
[_recordButton.titleLabel setFont:[UIFont systemFontOfSize:15.0f]];
|
||
[_recordButton.layer setMasksToBounds:YES];
|
||
[_recordButton.layer setCornerRadius:4.0f];
|
||
[_recordButton.layer setBorderWidth:0.5f];
|
||
[_recordButton.layer setBorderColor:[UIColor d_colorWithColorLight:TLine_Color dark:TLine_Color_Dark].CGColor];
|
||
[_recordButton addTarget:self action:@selector(recordBtnDown:) forControlEvents:UIControlEventTouchDown];
|
||
[_recordButton addTarget:self action:@selector(recordBtnUp:) forControlEvents:UIControlEventTouchUpInside];
|
||
[_recordButton addTarget:self action:@selector(recordBtnCancel:) forControlEvents:UIControlEventTouchUpOutside | UIControlEventTouchCancel];
|
||
[_recordButton addTarget:self action:@selector(recordBtnExit:) forControlEvents:UIControlEventTouchDragExit];
|
||
[_recordButton addTarget:self action:@selector(recordBtnEnter:) forControlEvents:UIControlEventTouchDragEnter];
|
||
[_recordButton setTitle:TUIKitLocalizableString(TUIKitInputHoldToTalk) forState:UIControlStateNormal];
|
||
[_recordButton setTitleColor:[UIColor d_colorWithColorLight:TText_Color dark:TText_Color_Dark] forState:UIControlStateNormal];
|
||
_recordButton.hidden = YES;
|
||
[self addSubview:_recordButton];
|
||
|
||
_inputTextView = [[TUIResponderTextView alloc] init];
|
||
_inputTextView.delegate = self;
|
||
[_inputTextView setFont:[UIFont systemFontOfSize:16]];
|
||
[_inputTextView.layer setMasksToBounds:YES];
|
||
[_inputTextView.layer setCornerRadius:4.0f];
|
||
[_inputTextView.layer setBorderWidth:0.5f];
|
||
[_inputTextView.layer setBorderColor:TUICoreDynamicColor(@"separtor_color", @"#FFFFFF").CGColor];
|
||
_inputTextView.backgroundColor = TUIChatDynamicColor(@"chat_input_bg_color", @"#FFFFFF");
|
||
_inputTextView.textColor = TUIChatDynamicColor(@"chat_input_text_color", @"#000000");
|
||
[_inputTextView setReturnKeyType:UIReturnKeySend];
|
||
[self addSubview:_inputTextView];
|
||
}
|
||
|
||
- (void)defaultLayout
|
||
{
|
||
_lineView.frame = CGRectMake(0, 0, Screen_Width, TLine_Heigh);
|
||
CGSize buttonSize = TTextView_Button_Size;
|
||
CGFloat buttonOriginY = (TTextView_Height - buttonSize.height) * 0.5;
|
||
_micButton.frame = CGRectMake(TTextView_Margin, buttonOriginY, buttonSize.width, buttonSize.height);
|
||
_keyboardButton.frame = _micButton.frame;
|
||
_moreButton.frame = CGRectMake(Screen_Width - buttonSize.width - TTextView_Margin, buttonOriginY, buttonSize.width, buttonSize.height);
|
||
_faceButton.frame = CGRectMake(_moreButton.frame.origin.x - buttonSize.width - TTextView_Margin, buttonOriginY, buttonSize.width, buttonSize.height);
|
||
|
||
CGFloat beginX = _micButton.frame.origin.x + _micButton.frame.size.width + TTextView_Margin;
|
||
CGFloat endX = _faceButton.frame.origin.x - TTextView_Margin;
|
||
_recordButton.frame = CGRectMake(beginX, (TTextView_Height - TTextView_TextView_Height_Min) * 0.5, endX - beginX, TTextView_TextView_Height_Min);
|
||
_inputTextView.frame = _recordButton.frame;
|
||
}
|
||
|
||
- (void)layoutButton:(CGFloat)height
|
||
{
|
||
CGRect frame = self.frame;
|
||
CGFloat offset = height - frame.size.height;
|
||
frame.size.height = height;
|
||
self.frame = frame;
|
||
|
||
CGSize buttonSize = TTextView_Button_Size;
|
||
CGFloat bottomMargin = (TTextView_Height - buttonSize.height) * 0.5;
|
||
CGFloat originY = frame.size.height - buttonSize.height - bottomMargin;
|
||
|
||
CGRect faceFrame = _faceButton.frame;
|
||
faceFrame.origin.y = originY;
|
||
_faceButton.frame = faceFrame;
|
||
|
||
CGRect moreFrame = _moreButton.frame;
|
||
moreFrame.origin.y = originY;
|
||
_moreButton.frame = moreFrame;
|
||
|
||
CGRect voiceFrame = _micButton.frame;
|
||
voiceFrame.origin.y = originY;
|
||
_micButton.frame = voiceFrame;
|
||
|
||
_keyboardButton.frame = _faceButton.frame;
|
||
|
||
if(_delegate && [_delegate respondsToSelector:@selector(inputBar:didChangeInputHeight:)]){
|
||
[_delegate inputBar:self didChangeInputHeight:offset];
|
||
}
|
||
}
|
||
|
||
- (void)clickVoiceBtn:(UIButton *)sender
|
||
{
|
||
_recordButton.hidden = NO;
|
||
_inputTextView.hidden = YES;
|
||
_micButton.hidden = YES;
|
||
_keyboardButton.hidden = NO;
|
||
_faceButton.hidden = NO;
|
||
[_inputTextView resignFirstResponder];
|
||
[self layoutButton:TTextView_Height];
|
||
if(_delegate && [_delegate respondsToSelector:@selector(inputBarDidTouchMore:)]){
|
||
[_delegate inputBarDidTouchVoice:self];
|
||
}
|
||
_keyboardButton.frame = _micButton.frame;
|
||
}
|
||
|
||
- (void)clickKeyboardBtn:(UIButton *)sender
|
||
{
|
||
_micButton.hidden = NO;
|
||
_keyboardButton.hidden = YES;
|
||
_recordButton.hidden = YES;
|
||
_inputTextView.hidden = NO;
|
||
_faceButton.hidden = NO;
|
||
[self layoutButton:_inputTextView.frame.size.height + 2 * TTextView_Margin];
|
||
if(_delegate && [_delegate respondsToSelector:@selector(inputBarDidTouchKeyboard:)]){
|
||
[_delegate inputBarDidTouchKeyboard:self];
|
||
}
|
||
}
|
||
|
||
- (void)clickFaceBtn:(UIButton *)sender
|
||
{
|
||
_micButton.hidden = NO;
|
||
_faceButton.hidden = YES;
|
||
_keyboardButton.hidden = NO;
|
||
_recordButton.hidden = YES;
|
||
_inputTextView.hidden = NO;
|
||
if(_delegate && [_delegate respondsToSelector:@selector(inputBarDidTouchFace:)]){
|
||
[_delegate inputBarDidTouchFace:self];
|
||
}
|
||
_keyboardButton.frame = _faceButton.frame;
|
||
}
|
||
|
||
- (void)clickMoreBtn:(UIButton *)sender
|
||
{
|
||
if(_delegate && [_delegate respondsToSelector:@selector(inputBarDidTouchMore:)]){
|
||
[_delegate inputBarDidTouchMore:self];
|
||
}
|
||
}
|
||
|
||
- (void)recordBtnDown:(UIButton *)sender
|
||
{
|
||
AVAudioSessionRecordPermission permission = AVAudioSession.sharedInstance.recordPermission;
|
||
//在此添加新的判定 undetermined,否则新安装后的第一次询问会出错。新安装后的第一次询问为 undetermined,而非 denied。
|
||
if (permission == AVAudioSessionRecordPermissionDenied || permission == AVAudioSessionRecordPermissionUndetermined) {
|
||
[AVAudioSession.sharedInstance requestRecordPermission:^(BOOL granted) {
|
||
if (!granted) {
|
||
UIAlertController *ac = [UIAlertController alertControllerWithTitle:TUIKitLocalizableString(TUIKitInputNoMicTitle) message:TUIKitLocalizableString(TUIKitInputNoMicTips) preferredStyle:UIAlertControllerStyleAlert];
|
||
[ac addAction:[UIAlertAction actionWithTitle:TUIKitLocalizableString(TUIKitInputNoMicOperateLater) style:UIAlertActionStyleCancel handler:nil]];
|
||
[ac addAction:[UIAlertAction actionWithTitle:TUIKitLocalizableString(TUIKitInputNoMicOperateEnable) style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
|
||
UIApplication *app = [UIApplication sharedApplication];
|
||
NSURL *settingsURL = [NSURL URLWithString:UIApplicationOpenSettingsURLString];
|
||
if ([app canOpenURL:settingsURL]) {
|
||
[app openURL:settingsURL];
|
||
}
|
||
}]];
|
||
dispatch_async(dispatch_get_main_queue(), ^{
|
||
[self.mm_viewController presentViewController:ac animated:YES completion:nil];
|
||
});
|
||
}
|
||
}];
|
||
return;
|
||
}
|
||
//在此包一层判断,添加一层保护措施。
|
||
if(permission == AVAudioSessionRecordPermissionGranted){
|
||
if(!_record){
|
||
_record = [[TUIRecordView alloc] init];
|
||
_record.frame = [UIScreen mainScreen].bounds;
|
||
}
|
||
[self.window addSubview:_record];
|
||
_recordStartTime = [NSDate date];
|
||
[_record setStatus:Record_Status_Recording];
|
||
_recordButton.backgroundColor = [UIColor lightGrayColor];
|
||
[_recordButton setTitle:TUIKitLocalizableString(TUIKitInputReleaseToSend) forState:UIControlStateNormal]; // @"松开 结束"
|
||
[self startRecord];
|
||
}
|
||
}
|
||
|
||
- (void)recordBtnUp:(UIButton *)sender
|
||
{
|
||
if (AVAudioSession.sharedInstance.recordPermission == AVAudioSessionRecordPermissionDenied) {
|
||
return;
|
||
}
|
||
_recordButton.backgroundColor = [UIColor clearColor];
|
||
[_recordButton setTitle:TUIKitLocalizableString(TUIKitInputHoldToTalk) forState:UIControlStateNormal]; // @"按住 说话"
|
||
NSTimeInterval interval = [[NSDate date] timeIntervalSinceDate:_recordStartTime];
|
||
if(interval < 1){
|
||
[_record setStatus:Record_Status_TooShort];
|
||
[self cancelRecord];
|
||
__weak typeof(self) ws = self;
|
||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||
[ws.record removeFromSuperview];
|
||
});
|
||
} else if(interval > 60) {
|
||
[_record setStatus:Record_Status_TooLong];
|
||
if (self.recordTimer == nil) {
|
||
// 此时超时回调已经在处理了,忽略
|
||
return;
|
||
}
|
||
[self cancelRecord];
|
||
__weak typeof(self) ws = self;
|
||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||
[ws.record removeFromSuperview];
|
||
});
|
||
} else{
|
||
[_record removeFromSuperview];
|
||
NSString *path = [self stopRecord];
|
||
_record = nil;
|
||
if (path) {
|
||
if(_delegate && [_delegate respondsToSelector:@selector(inputBar:didSendVoice:)]){
|
||
[_delegate inputBar:self didSendVoice:path];
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
- (void)recordBtnCancel:(UIButton *)sender
|
||
{
|
||
[_record removeFromSuperview];
|
||
_recordButton.backgroundColor = [UIColor clearColor];
|
||
[_recordButton setTitle:TUIKitLocalizableString(TUIKitInputHoldToTalk) forState:UIControlStateNormal]; // @"按住 说话"
|
||
[self cancelRecord];
|
||
}
|
||
|
||
- (void)recordBtnExit:(UIButton *)sender
|
||
{
|
||
[_record setStatus:Record_Status_Cancel];
|
||
[_recordButton setTitle:TUIKitLocalizableString(TUIKitInputReleaseToCancel) forState:UIControlStateNormal]; // @"松开 取消"
|
||
}
|
||
|
||
- (void)recordBtnEnter:(UIButton *)sender
|
||
{
|
||
[_record setStatus:Record_Status_Recording];
|
||
[_recordButton setTitle:TUIKitLocalizableString(TUIKitInputReleaseToSend) forState:UIControlStateNormal]; // @"松开 结束"
|
||
}
|
||
|
||
#pragma mark - talk
|
||
|
||
- (void)textViewDidBeginEditing:(UITextView *)textView
|
||
{
|
||
self.keyboardButton.hidden = YES;
|
||
self.micButton.hidden = NO;
|
||
self.faceButton.hidden = NO;
|
||
}
|
||
|
||
- (void)textViewDidChange:(UITextView *)textView
|
||
{
|
||
CGSize size = [_inputTextView sizeThatFits:CGSizeMake(_inputTextView.frame.size.width, TTextView_TextView_Height_Max)];
|
||
CGFloat oldHeight = _inputTextView.frame.size.height;
|
||
CGFloat newHeight = size.height;
|
||
|
||
if(newHeight > TTextView_TextView_Height_Max){
|
||
newHeight = TTextView_TextView_Height_Max;
|
||
}
|
||
if(newHeight < TTextView_TextView_Height_Min){
|
||
newHeight = TTextView_TextView_Height_Min;
|
||
}
|
||
if(oldHeight == newHeight){
|
||
return;
|
||
}
|
||
|
||
__weak typeof(self) ws = self;
|
||
[UIView animateWithDuration:0.3 animations:^{
|
||
CGRect textFrame = ws.inputTextView.frame;
|
||
textFrame.size.height += newHeight - oldHeight;
|
||
ws.inputTextView.frame = textFrame;
|
||
[ws layoutButton:newHeight + 2 * TTextView_Margin];
|
||
}];
|
||
}
|
||
|
||
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
|
||
{
|
||
if([text isEqualToString:@"\n"]){
|
||
if(_delegate && [_delegate respondsToSelector:@selector(inputBar:didSendText:)]) {
|
||
NSString *sp = [textView.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
|
||
if (sp.length == 0) {
|
||
UIAlertController *ac = [UIAlertController alertControllerWithTitle:TUIKitLocalizableString(TUIKitInputBlankMessageTitle) message:nil preferredStyle:UIAlertControllerStyleAlert];
|
||
[ac addAction:[UIAlertAction actionWithTitle:TUIKitLocalizableString(Confirm) style:UIAlertActionStyleDefault handler:nil]];
|
||
[self.mm_viewController presentViewController:ac animated:YES completion:nil];
|
||
} else {
|
||
[_delegate inputBar:self didSendText:textView.text];
|
||
[self clearInput];
|
||
}
|
||
}
|
||
return NO;
|
||
}
|
||
else if ([text isEqualToString:@""]) {
|
||
if (textView.text.length > range.location) {
|
||
// 一次性删除 [微笑] 这种表情消息
|
||
if ([textView.text characterAtIndex:range.location] == ']') {
|
||
NSUInteger location = range.location;
|
||
NSUInteger length = range.length;
|
||
int left = 91; // '[' 对应的ascii码
|
||
int right = 93; // ']' 对应的ascii码
|
||
while (location != 0) {
|
||
location --;
|
||
length ++ ;
|
||
int c = (int)[textView.text characterAtIndex:location]; // 将字符转换成ascii码,复制给int 避免越界
|
||
if (c == left) {
|
||
textView.text = [textView.text stringByReplacingCharactersInRange:NSMakeRange(location, length) withString:@""];
|
||
return NO;
|
||
}
|
||
else if (c == right) {
|
||
return YES;
|
||
}
|
||
}
|
||
}
|
||
// 一次性删除 @xxx 这种 @ 消息
|
||
else if ([textView.text characterAtIndex:range.location] == ' ') {
|
||
NSUInteger location = range.location;
|
||
NSUInteger length = range.length;
|
||
int at = 64; // '@' 对应的ascii码
|
||
while (location != 0) {
|
||
location --;
|
||
length ++ ;
|
||
int c = (int)[textView.text characterAtIndex:location]; // 将字符转成ascii码,复制给int,避免越界
|
||
if (c == at) {
|
||
NSString *atText = [textView.text substringWithRange:NSMakeRange(location, length)];
|
||
textView.text = [textView.text stringByReplacingCharactersInRange:NSMakeRange(location, length) withString:@""];
|
||
if (self.delegate && [self.delegate respondsToSelector:@selector(inputBar:didDeleteAt:)]) {
|
||
[self.delegate inputBar:self didDeleteAt:atText];
|
||
}
|
||
return NO;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
// 监听 @ 字符的输入,包含全角/半角
|
||
else if ([text isEqualToString:@"@"] || [text isEqualToString:@"@"]) {
|
||
if (self.delegate && [self.delegate respondsToSelector:@selector(inputBarDidInputAt:)]) {
|
||
[self.delegate inputBarDidInputAt:self];
|
||
}
|
||
}
|
||
return YES;
|
||
}
|
||
|
||
- (void)onDeleteBackward:(TUIResponderTextView *)textView
|
||
{
|
||
// 点击键盘上的删除按钮
|
||
if (self.delegate && [self.delegate respondsToSelector:@selector(inputBarDidDeleteBackward:)]) {
|
||
[self.delegate inputBarDidDeleteBackward:self];
|
||
}
|
||
}
|
||
|
||
- (void)clearInput
|
||
{
|
||
_inputTextView.text = @"";
|
||
[self textViewDidChange:_inputTextView];
|
||
}
|
||
|
||
- (NSString *)getInput
|
||
{
|
||
return _inputTextView.text;
|
||
}
|
||
|
||
- (void)addEmoji:(NSString *)emoji
|
||
{
|
||
[_inputTextView setText:[_inputTextView.text stringByAppendingString:emoji]];
|
||
if(_inputTextView.contentSize.height > TTextView_TextView_Height_Max){
|
||
float offset = _inputTextView.contentSize.height - _inputTextView.frame.size.height;
|
||
[_inputTextView scrollRectToVisible:CGRectMake(0, offset, _inputTextView.frame.size.width, _inputTextView.frame.size.height) animated:YES];
|
||
}
|
||
[self textViewDidChange:_inputTextView];
|
||
}
|
||
|
||
- (void)backDelete
|
||
{
|
||
[self textView:_inputTextView shouldChangeTextInRange:NSMakeRange(_inputTextView.text.length - 1, 1) replacementText:@""];
|
||
[self textViewDidChange:_inputTextView];
|
||
}
|
||
|
||
- (void)updateTextViewFrame
|
||
{
|
||
[self textViewDidChange:[UITextView new]];
|
||
}
|
||
|
||
- (void)changeToKeyboard
|
||
{
|
||
[self clickKeyboardBtn:self.keyboardButton];
|
||
}
|
||
|
||
- (void)startRecord
|
||
{
|
||
AVAudioSession *session = [AVAudioSession sharedInstance];
|
||
NSError *error = nil;
|
||
[session setCategory:AVAudioSessionCategoryPlayAndRecord error:&error];
|
||
[session setActive:YES error:&error];
|
||
|
||
//设置参数
|
||
NSDictionary *recordSetting = [[NSDictionary alloc] initWithObjectsAndKeys:
|
||
//采样率 8000/11025/22050/44100/96000(影响音频的质量)
|
||
[NSNumber numberWithFloat: 8000.0],AVSampleRateKey,
|
||
// 音频格式
|
||
[NSNumber numberWithInt: kAudioFormatMPEG4AAC],AVFormatIDKey,
|
||
//采样位数 8、16、24、32 默认为16
|
||
[NSNumber numberWithInt:16],AVLinearPCMBitDepthKey,
|
||
// 音频通道数 1 或 2
|
||
[NSNumber numberWithInt: 1], AVNumberOfChannelsKey,
|
||
//录音质量
|
||
[NSNumber numberWithInt:AVAudioQualityHigh],AVEncoderAudioQualityKey,
|
||
nil];
|
||
|
||
NSString *path = [TUIKit_Voice_Path stringByAppendingString:[TUITool genVoiceName:nil withExtension:@"m4a"]];
|
||
NSURL *url = [NSURL fileURLWithPath:path];
|
||
_recorder = [[AVAudioRecorder alloc] initWithURL:url settings:recordSetting error:nil];
|
||
_recorder.meteringEnabled = YES;
|
||
[_recorder prepareToRecord];
|
||
[_recorder record];
|
||
[_recorder updateMeters];
|
||
|
||
_recordTimer = [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(recordTick:) userInfo:nil repeats:YES];
|
||
}
|
||
|
||
- (void)recordTick:(NSTimer *)timer{
|
||
[_recorder updateMeters];
|
||
float power = [_recorder averagePowerForChannel:0];
|
||
[_record setPower:power];
|
||
|
||
//在此处添加一个时长判定,如果时长超过60s,则取消录制,提示时间过长,同时不再显示 recordView。
|
||
//此处使用 recorder 的属性,使得录音结果尽量精准。注意:由于语音的时长为整形,所以 60.X 秒的情况会被向下取整。但因为 ticker 0.5秒执行一次,所以因该都会在超时时显示为60s
|
||
NSTimeInterval interval = _recorder.currentTime;
|
||
if(interval >= 55 && interval < 60){
|
||
NSInteger seconds = 60 - interval;
|
||
NSString *secondsString = [NSString stringWithFormat:TUIKitLocalizableString(TUIKitInputWillFinishRecordInSeconds),(long)seconds + 1];//此处加long,是为了消除编译器警告。此处 +1 是为了向上取整,优化时间逻辑。
|
||
_record.title.text = secondsString;
|
||
}
|
||
if(interval >= 60){
|
||
NSString *path = [self stopRecord];
|
||
[_record setStatus:Record_Status_TooLong];
|
||
__weak typeof(self) ws = self;
|
||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||
[ws.record removeFromSuperview];
|
||
});
|
||
if (path) {
|
||
if(_delegate && [_delegate respondsToSelector:@selector(inputBar:didSendVoice:)]){
|
||
[_delegate inputBar:self didSendVoice:path];
|
||
}
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
|
||
- (NSString *)stopRecord
|
||
{
|
||
if(_recordTimer){
|
||
[_recordTimer invalidate];
|
||
_recordTimer = nil;
|
||
}
|
||
if([_recorder isRecording]){
|
||
[_recorder stop];
|
||
}
|
||
return _recorder.url.path;
|
||
}
|
||
|
||
- (void)cancelRecord
|
||
{
|
||
if(_recordTimer){
|
||
[_recordTimer invalidate];
|
||
_recordTimer = nil;
|
||
}
|
||
if([_recorder isRecording]){
|
||
[_recorder stop];
|
||
}
|
||
NSString *path = _recorder.url.path;
|
||
if([[NSFileManager defaultManager] fileExistsAtPath:path]){
|
||
[[NSFileManager defaultManager] removeItemAtPath:path error:nil];
|
||
}
|
||
}
|
||
|
||
@end
|