iOS开发-类似微信录音上滑取消功能

  • 前言
    • 效果
    • 代码
      • 先自定义UIButton
      • 使用
      • 监听上下滑动代码

前言

在社交媒体中开发中遇到需要做类似微信录音上滑取消功能,例子,虽然不是很好看,但是细节满满哦,另外参数可以自己重置,满足自己产品的需求。

效果

  • 按住Record开始录音
  • 向上取消录音并且cancel出现伴随下移动作
  • 如果录音长度短于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;@endNS_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]];//WAVMessageRadioAVAudioSession *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,                          // 采样位数 默认 16AVNumberOfChannelsKey  : @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.间隔时间大于1sif([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~-50NSLog(@"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]];//WAVMessageRadioNSString *amrRecordFilePath = [NSTemporaryDirectory() stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.amr",kMessageAMRMessageRadio]];//AMRMessageRadioNSFileManager *fileManager = [NSFileManager defaultManager];[fileManager removeItemAtPath:wavRecordFilePath error:nil];[fileManager removeItemAtPath:amrRecordFilePath error:nil];
}- (void)_stopAudioRecorder {[self.audioRecorder stop];//恢复外部音乐[[AVAudioSession sharedInstance] setActive:NOwithOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivationerror: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~-50NSLog(@"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);
}

iOS开发-类似微信录音上滑取消功能相关推荐

  1. mpvue vue 长按录音,上滑取消,下拉恢复

    需求: mpvue 开发小程序实现 按住录音上滑取消,下拉恢复 知识点: touchstart touchend touchmove 事件 效果: <button@touchstart=&quo ...

  2. 仿微信录音功能-(声波动画,上滑取消,超时截取,倒计时提醒)

    序言 最近开发了一个语音输入控件,UI效果和微信的保持基本一直,除了颜色不一样.具体的功能如下 动画效果和微信一样,都是通过声音的分贝大小驱动动画的大小 如果声音过小,会进入监听模式,(一个小波浪从右 ...

  3. uniapp小程序实现长按录音、上滑取消的与语言录入模块(CSS实现语音音阶动画效果)

    这里写目录标题 语言录入模块 实现效果 HTML部分 JS部分 CSS部分 总结 语言录入模块 实现效果 HTML部分 代码如下: <template><view :class=&q ...

  4. Android仿微信发送语音消息动态提示,支持上滑取消发送

    Android仿微信发送语音消息动态提示,支持上滑取消发送 先来几张图说明一下,简单直接: 是不是看了图片就秒懂 了. 下面来分析代码实现,直接撸代码. 主页面 AudioSendActivity.j ...

  5. php 微信 语音,PHP语言微信开发:微信录音临时转永久存储

    本文主要向大家介绍了PHP语言微信开发:微信录音临时转永久存储,通过具体的内容向大家展示,希望对大家学习php语言有所帮助. 最近做开发的时候碰到了这个问题,甲方希望用户在微信端的录音能够一直有效.就 ...

  6. iOS开发通过微信学习WCDB(二)

      通过<iOS开发通过微信学习WCDB(一)>这篇博客,相信大家对WCDB已经有了一个简单的了解和认识.这篇文章主要是为了进一步深入的学习 ###数据库加密   上篇文章中提到了,自己在 ...

  7. H5开发在微信浏览器上,出现“白屏”问题

    微信开发: H5开发在微信浏览器上,出现"白屏"问题 在开发微信公众号的页面时,应该很多开发者会出现: 从菜单栏点击跳转到页面时出现白屏或者授权完成重定向出现白屏. 大致导致白屏的 ...

  8. iOS开发-关于微信WCDB的使用 WCDB嵌套模型的使用

    iOS开发-关于微信WCDB的使用 WCDB嵌套模型的使用 前言 开发前准备 开发 关于生成WCDB文件 选择new file即可找到 关于嵌套模型的生成 分两步 选择new file即可找到 增删改 ...

  9. iOS开发入门——模拟器方向判断及基本功能

    iOS开发入门--模拟器方向判断及基本功能 方向判断简单实用 手机模拟器吧,嗯...很多时候我们可能会遇到手机横屏之后图像没变的情况,嗯?怎么回事?这次我们就先来看看这种情况,做一个简单的判断. im ...

最新文章

  1. antd-react-mobile(踩坑记录)
  2. LINUX IRC使用
  3. java 反射 本类,关于Java反射中基本类型的class有关问题
  4. spark rest_Spark简介,您的下一个REST Java框架
  5. Web框架中的ORM框架
  6. Set和Map集合的比较
  7. 图例 | Java混合模式分析之火焰图实例
  8. PTA 数据结构与算法题目集 6-1
  9. Matlab与Access数据库的连接
  10. 文强+光裕+唐骏,告诉我们什么?
  11. 学习python: 2.x 和 3.x的区别
  12. 供应XBF-01型多功存储介质粉碎机
  13. Delphi利用字符串序列号对象
  14. PostGIS几何图形操作
  15. mysql 父子关系查询,父子关系-SQL查询
  16. 斯阔谷冬奥会首次使用计算机,中国与冬奥会首次接触在美国加州,举办地以印第安女人命名...
  17. 无线局域网设备安装与调试
  18. 油菜籽的全球与中国市场2022-2028年:技术、参与者、趋势、市场规模及占有率研究报告
  19. 【转载】研究生退学记——谨以此记录我半途而废的研究生生涯
  20. nginx的http_rewrite模块的rewrite指令

热门文章

  1. python 发邮件 带附件
  2. 基于无人机摄影测量技术的桥梁检测
  3. 一文读懂 非root用户正确编译安装 protobuf —— 附 CMakeLists.txt 配置
  4. 麻省理工学院|软件构造|课程翻译
  5. 基于spring boot的奖助学金评审系统毕业设计源码031035
  6. ERP(会计)-主要会计科目表名称
  7. 删除 linux的ln文件夹,linux下添加链接与删除链接(ln命令的用法)
  8. python小波包分解_小波包获得某个节点信号的几个细节问题
  9. 通过RabbitMQ 进行消息通知
  10. 虚拟机ubuntu设置和windows的共享文件夹