iOS開発-WeChatの録音アップおよびダウンキャンセル機能と同様

iOS開発-WeChatの録音アップおよびダウンキャンセル機能と同様

序文

ソーシャルメディアの開発では、WeChat録音のスライドアップキャンセルと同様の機能を実行する必要があります。例はあまり美しくはありませんが、詳細が満載です。また、パラメータは自分でリセットできます。あなた自身の製品のニーズを満たします。

効果

  • 録音を長押しして録音を開始します
  • 上向きに録音をキャンセルすると、下向きにキャンセルが表示されます
  • 録音長が1秒未満の場合は再録音してください
    ここに画像の説明を挿入

コード

最初にUIButtonをカスタマイズします

  • SwipVoiceButton.h
#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN
@protocol SwipVoiceButtonDelegate <NSObject>
@optional
- (void)swipVoiceButtonOffset:(CGFloat)offset; //上移偏移量

@end
static CGFloat const kOverRangeY = 50.0f;
@interface SwipVoiceButton : UIButton

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

@end

NS_ASSUME_NONNULL_END
  • SwipVoiceButton.m
#import "SwipVoiceButton.h"

@implementation SwipVoiceButton

- (BOOL)continueTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event {
    
    
    CGPoint point = [touch locationInView:self];
    CGFloat offset = 0;
    if(point.y < -kOverRangeY) {
    
     //上移
        offset = -kOverRangeY;
    } else if(point.y > 0) {
    
    
        offset = 0;
    } else {
    
    
        offset = point.y;
    }
    //NSLog(@"point%f", offset);
    if(_delegate && [_delegate respondsToSelector:@selector(swipVoiceButtonOffset:)]) {
    
    
        [_delegate swipVoiceButtonOffset:offset];
    }
    return [super continueTrackingWithTouch:touch withEvent:event];
}

@end

使用する

  • ViewController.m
#import "ViewController.h"
#import "SwipVoiceButton.h"
#import <AVFoundation/AVFoundation.h>

#define kForMaxTime 59
static NSString *const kMessageWAVMessageRadio = @"WAVMessageRadio";
static NSString *const kMessageAMRMessageRadio = @"AMRMessageRadio";
@interface ViewController () <SwipVoiceButtonDelegate>

@property(nonatomic, strong) SwipVoiceButton *clickVoiceButton;
@property(nonatomic, strong) AVAudioRecorder *audioRecorder;
@property(nonatomic, strong) NSTimer *timer;
@property(nonatomic, assign) NSInteger count;

@property(nonatomic, strong) UILabel *tipLabel;
@property(nonatomic, strong) UILabel *cancelLabel;

@end

@implementation ViewController

- (void)viewDidLoad {
    
    
    [super viewDidLoad];
    [self setViewControllerUI];
}

- (void)setViewControllerUI {
    
    
    [self.view addSubview:self.clickVoiceButton];
    [self.view addSubview:self.tipLabel];
    [self.view addSubview:self.cancelLabel];
}

- (void)viewWillLayoutSubviews {
    
    
    [super viewWillLayoutSubviews];
    self.clickVoiceButton.frame = CGRectMake((self.view.frame.size.width / 2) - 22, self.view.frame.size.height - 120, 44, 44);
    self.tipLabel.frame = CGRectMake(0, (self.view.frame.size.height / 2) + 50, self.view.frame.size.width, 20);
    self.cancelLabel.frame = CGRectMake(0, (self.view.frame.size.height / 2) - 50, self.view.frame.size.width, 20);
}

- (UILabel *)tipLabel {
    
    
    if(_tipLabel == nil) {
    
    
        _tipLabel = [[UILabel alloc]init];
        _tipLabel.textColor = [UIColor blackColor];
        _tipLabel.font = [UIFont systemFontOfSize:15];
        _tipLabel.textAlignment = NSTextAlignmentCenter;
        [_tipLabel sizeToFit];
    }
    return _tipLabel;
}

- (UILabel *)cancelLabel {
    
    
    if(_cancelLabel == nil) {
    
    
        _cancelLabel = [[UILabel alloc]init];
        _cancelLabel.text = @"Cancel";
        _cancelLabel.textColor = [UIColor blackColor];
        _cancelLabel.font = [UIFont systemFontOfSize:15];
        _cancelLabel.textAlignment = NSTextAlignmentCenter;
        [_cancelLabel sizeToFit];
        _cancelLabel.hidden = YES;
    }
    return _cancelLabel;
}

- (SwipVoiceButton *)clickVoiceButton {
    
    
    if(_clickVoiceButton == nil) {
    
    
        _clickVoiceButton = [[SwipVoiceButton alloc]init];
        _clickVoiceButton.backgroundColor = [UIColor yellowColor];
        _clickVoiceButton.layer.cornerRadius = 22;
        _clickVoiceButton.layer.masksToBounds = YES;
        [_clickVoiceButton setTitle:@"Record" forState:UIControlStateNormal];
        _clickVoiceButton.titleLabel.font = [UIFont systemFontOfSize:10];
        [_clickVoiceButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
        _clickVoiceButton.delegate = self;
        
        [_clickVoiceButton addTarget:self action:@selector(startRecordVoice) forControlEvents:UIControlEventTouchDown]; //开始录音
        [_clickVoiceButton addTarget:self action:@selector(cancelRecordVoice) forControlEvents:UIControlEventTouchUpOutside]; //取消录音
        [_clickVoiceButton addTarget:self action:@selector(endRecordVoice) forControlEvents:UIControlEventTouchUpInside]; //录音结束
        [_clickVoiceButton addTarget:self action:@selector(upswipeCancelRecordVoice) forControlEvents:UIControlEventTouchDragExit]; //向上滑动 提示松开取消录音
        [_clickVoiceButton addTarget:self action:@selector(downSwipeContinueRecordVoice) forControlEvents:UIControlEventTouchDragEnter]; //手指重新滑动到范围内 提示向上取消录音
    }
    return _clickVoiceButton;
}

- (AVAudioRecorder *)audioRecorder {
    
    
    if (_audioRecorder == nil) {
    
    
        NSString *wavRecordFilePath = [NSTemporaryDirectory() stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.wav",kMessageWAVMessageRadio]];//WAVMessageRadio
        
        AVAudioSession *audioSession = [AVAudioSession sharedInstance];
        [audioSession setCategory:AVAudioSessionCategoryPlayAndRecord error:nil];
        [audioSession overrideOutputAudioPort:AVAudioSessionPortOverrideSpeaker error:nil];
        [audioSession setActive:YES error:nil];
        
        NSDictionary *recordSetting = @{
    
     AVSampleRateKey        : @8000.0,                      // 采样率
                                         AVFormatIDKey          : @(kAudioFormatLinearPCM),     // 音频格式
                                         AVLinearPCMBitDepthKey : @16,                          // 采样位数 默认 16
                                         AVNumberOfChannelsKey  : @1                            // 通道的数目
                                         };
        _audioRecorder = [[AVAudioRecorder alloc] initWithURL:[NSURL URLWithString:wavRecordFilePath] settings:recordSetting error:nil];
        _audioRecorder.meteringEnabled = YES;
    }
    return _audioRecorder;
}

#pragma mark - 按钮方法

/*
 0.录音
    0.0 大于1秒
        1.录制完毕
 0.1 小于一秒重新录制
 */
- (void)startRecordVoice {
    
     //开始录音
    NSLog(@"%@%s", NSStringFromClass([self class]), __func__);
    //0.开始录音
    self.tipLabel.text = @"开始录音";
    //1.开始录音回调
    [self _beginAudioRecorder];
    //开启60s倒计时
    [self startMaxTimeTask];
}

- (void)endRecordVoice {
    
     //录音结束
    NSLog(@"%@%s", NSStringFromClass([self class]), __func__);
    [self endMaxTimeTask];
    //-1.间隔时间大于1s
    if([self _canSendRecordVoice]) {
    
     //可以发送
        //0.展示发送录音动画
        self.tipLabel.text = @"录音完成发送录音 1s 后重置";
        [self.tipLabel performSelector:@selector(setText:) withObject:@"开始录音" afterDelay:1.0];
    } else {
    
     //不可以发送
        //0.重新录音
        self.tipLabel.text = @"重新录音";
        self.cancelLabel.hidden = YES;
    }
}

- (void)upswipeCancelRecordVoice {
    
     //向上滑动 提示松开取消录音
    //NSLog(@"%@%s", NSStringFromClass([self class]), __func__);
    self.tipLabel.text = @"松开取消录音";
}

- (void)cancelRecordVoice {
    
     //向上取消后
    NSLog(@"%@%s", NSStringFromClass([self class]), __func__);
    //0.重新录音
    self.tipLabel.text = @"重新录音";
    //1.录音取消删除回调
    [self _deleteAudioRecorder];
    //2.取消计时器
    [self endMaxTimeTask];
}

- (void)downSwipeContinueRecordVoice {
    
     //手指重新滑动到范围内 提示向上取消录音
    //NSLog(@"%@-%s", NSStringFromClass([self class]), __func__);
    self.tipLabel.text = @"向上取消录音";
}

#pragma mark - 按钮方法 end

#pragma mark - MessageChatSwipVoiceButtonDelegate

- (void)swipVoiceButtonOffset:(CGFloat)offset {
    
     //上移偏移量 0~-50
    NSLog(@"offset %f", offset);
    if(fabs(offset) > 10) {
    
     //取消录音
        self.cancelLabel.hidden = NO;
    } else {
    
     //重回录音
        self.cancelLabel.hidden = YES;
    }
    
    self.cancelLabel.center = CGPointMake(self.view.center.x, self.view.center.y - offset);
}

#pragma mark - MessageChatSwipVoiceButtonDelegate end

#pragma mark - audioRecorder方法

- (void)_beginAudioRecorder {
    
    
    [self.audioRecorder prepareToRecord];
    [self.audioRecorder record];
}

- (void)_deleteAudioRecorder {
    
    
    NSString *wavRecordFilePath = [NSTemporaryDirectory() stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.wav",kMessageWAVMessageRadio]];//WAVMessageRadio
    NSString *amrRecordFilePath = [NSTemporaryDirectory() stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.amr",kMessageAMRMessageRadio]];//AMRMessageRadio
    NSFileManager *fileManager = [NSFileManager defaultManager];
    [fileManager removeItemAtPath:wavRecordFilePath error:nil];
    [fileManager removeItemAtPath:amrRecordFilePath error:nil];
}

- (void)_stopAudioRecorder {
    
    
    [self.audioRecorder stop];
    //恢复外部音乐
    [[AVAudioSession sharedInstance] setActive:NO
                                   withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation
                                         error:nil];
}

#pragma mark - audioRecorder方法 end

#pragma mark - timer for max

- (void)startMaxTimeTask {
    
    
    self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(taskAction) userInfo:nil repeats:YES];
    [[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSDefaultRunLoopMode];
    _count = kForMaxTime;
}

- (void)endMaxTimeTask {
    
    
    [_timer invalidate];
    [_timer fire];
    _timer = nil;
}

- (void)taskAction {
    
    
    if(_count == 0) {
    
    
        [self endRecordVoice];
        [self endMaxTimeTask];
        NSLog(@"end record %ld", self.count);
    }
    NSLog(@"begian record %ld", self.count);
    _count --;
}

- (void)dealloc {
    
    
    [self endMaxTimeTask];
}

#pragma mark - timer for max end

#pragma mark - private method

- (BOOL)_canSendRecordVoice {
    
     //是否大于1s可以发送
    BOOL cansend = NO;
    if(self.audioRecorder.currentTime < 1.0f) {
    
     //时间小于1秒
        NSLog(@"Time too short!");
        cansend = NO;
    } else {
    
    
        cansend = YES;
    }
    [self _stopAudioRecorder];
    return cansend;
}

#pragma mark - private method end

@end

コードを上下にスワイプします

- (void)swipVoiceButtonOffset:(CGFloat)offset {
    
     //上移偏移量 0~-50
    NSLog(@"offset %f", offset);
    if(fabs(offset) > 10) {
    
     //取消录音
        self.cancelLabel.hidden = NO;
    } else {
    
     //重回录音
        self.cancelLabel.hidden = YES;
    }
    
    self.cancelLabel.center = CGPointMake(self.view.center.x, self.view.center.y - offset);
}

おすすめ

転載: blog.csdn.net/weixin_41732253/article/details/110142169