录制短视频的录制按钮边框计时效果
项目增加录制短视频功能, 需一录制功能按钮, 使用贝塞尔曲线结合shapelayer绘制按钮边框的计时功能
代码如下:
#import "YGRecordView.h"
#define BeforeRecord_LineWidth 2.0
#define BeforeRecord_LineColor UIColorFromRGBA(0xffffff, 1)
#define Record_LineWidth 5.0
#define Record_LineColor UIColorFromRGBA(0xffffff, 0.3)
#define Record_TotalTime 30.0
@interface YGRecordView ()
@property (nonatomic, strong) UIButton *closeButton;//返回按钮
@property (nonatomic, strong) UIButton *cameraButton;//切换相机按钮
@property (nonatomic, strong) UIButton *alertButton;//提示按钮
@property (nonatomic, strong) UIButton *recordButton;//录制按钮
@property (nonatomic, strong) CAShapeLayer *borderLayer;//录制边框
@property (nonatomic, strong) CAShapeLayer *progressLayer;//设置路径
@property (nonatomic, strong) CABasicAnimation *strokeAnimationStart;//动画
@property (nonatomic, strong) NSTimer *timer;//定时器
@property (nonatomic, assign) NSInteger times;//录制时间
@end
@implementation YGRecordView
- (instancetype)init
{
self = [super init];
if (self) {
[self setUI];
[self setFrame];
}
return self;
}
- (void)setUI {
for (int i = 0; i < 4; i ++) {
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
[self addSubview:button];
button.tag = 31 + i;
[button addTarget:self action:@selector(buttonClick:) forControlEvents:UIControlEventTouchUpInside];
if (i == 0) {
self.closeButton = button;
[_closeButton setImage:[UIImage imageNamed:@"record_close"] forState:UIControlStateNormal];
} else if (i == 1) {
self.cameraButton = button;
[_cameraButton setImage:[UIImage imageNamed:@"record_camera"] forState:UIControlStateNormal];
} else if (i == 2) {
self.alertButton = button;
_alertButton.hidden = YES;
_alertButton.userInteractionEnabled = NO;
[_alertButton setBackgroundImage:[UIImage imageNamed:@"record_alert_bg"] forState:UIControlStateNormal];
_alertButton.titleLabel.font = [UIFont systemFontOfSize:11.0];
[_alertButton setTitle:@"录制至少八秒以上" forState:UIControlStateNormal];
[_alertButton setTitleColor:UIColorFromRGBA(0xffffff, 0.8) forState:UIControlStateNormal];
_alertButton.titleEdgeInsets = UIEdgeInsetsMake(0, 0, 9, 0);
} else if (i == 3) {
self.recordButton = button;
_recordButton.backgroundColor = UIColorFromRGBA(0xffffff, 0.6);
[_recordButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
_recordButton.titleLabel.font = [UIFont systemFontOfSize:15.0];
}
}
}
- (void)setFrame {
self.frame = CGRectMake(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
//返回 && 切换摄像头
for (int i = 0; i < 2; i ++) {
UIButton *button = (UIButton *)[self viewWithTag:31 + i];
[button mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self).offset(0.06 * SCREEN_HEIGHT);
make.height.equalTo(self).multipliedBy(0.06);
make.width.equalTo(button.mas_height);
if (i == 0) {
make.left.equalTo(self).offset(13);
} else {
make.right.equalTo(self).offset(-13);
}
}];
}
//录制按钮
[_recordButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerX.equalTo(self);
make.bottom.equalTo(self).offset(- 0.052 * SCREEN_HEIGHT);
make.height.equalTo(self).multipliedBy(0.099);
make.width.equalTo(_recordButton.mas_height);
}];
//提示按钮
[_alertButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerX.equalTo(self);
make.bottom.equalTo(_recordButton.mas_top).offset(-0.02 * SCREEN_HEIGHT);
make.width.equalTo(self).multipliedBy(0.35);
make.height.equalTo(_alertButton.mas_width).multipliedBy(0.24);
}];
}
//设置圆角, 添加图层
- (void)layoutSubviews {
[super layoutSubviews];
CGFloat H = _recordButton.frame.size.height;
_recordButton.layer.masksToBounds = YES;
_recordButton.layer.cornerRadius = H / 2.0;
[self.layer addSublayer:self.borderLayer];
}
- (void)buttonClick:(UIButton *)sender {
if (sender.tag == 31 || sender.tag == 32) {
//点击返回或切换摄像头按钮
if (self.recordViewBlock) {
_recordViewBlock(sender.tag);
}
} else if (sender.tag == 34) {
//点击录制按钮
[self dealRecordWithSender:sender];
}
}
- (void)dealRecordWithSender:(UIButton *)sender {
sender.selected = !sender.selected;
if (sender.selected) {
//开始录制
[self startRecord];
} else {
//结束录制
[self stopRecordIsEnterBackground:NO];
}
}
//开始录制
- (void)startRecord {
_times = 0;
_alertButton.hidden = NO;
//修改录制按钮
_recordButton.backgroundColor = UIColorFromRGBA(0xff0000, 0.8);
//修改边框layer
_borderLayer.lineWidth = Record_LineWidth;
_borderLayer.strokeColor = Record_LineColor.CGColor;
//开启定时器
[self addTimer];
//开启动画
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self.layer addSublayer:self.progressLayer];
[self.progressLayer addAnimation:self.strokeAnimationStart forKey:nil];
});
//回调33 开始录制
if (self.recordViewBlock) {
_recordViewBlock(33);
}
}
//停止录制
- (void)stopRecordIsEnterBackground:(BOOL)is {
//移除动画
[self.layer removeAllAnimations];
[_progressLayer removeAllAnimations];
[_progressLayer removeFromSuperlayer];
//取消定时器
[self cancleTimer];
_alertButton.hidden = YES;
//恢复录制按钮
_recordButton.selected = NO;
_recordButton.backgroundColor = UIColorFromRGBA(0xffffff, 0.6);
[_recordButton setTitle:@"" forState:UIControlStateNormal];
//恢复边框layer
_borderLayer.lineWidth = BeforeRecord_LineWidth;
_borderLayer.strokeColor = BeforeRecord_LineColor.CGColor;
//回调 <=30 录制结束
if (self.recordViewBlock) {
//如果是进入后台调用的此方法则不回调
if (!is) {
_recordViewBlock(_times);
}
}
}
#pragma mark -
//添加定时器
- (void)addTimer {
if (_timer == nil) {
_timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(saveRecordTime) userInfo:nil repeats:YES];
}
[[NSRunLoop currentRunLoop] addTimer:_timer forMode:NSDefaultRunLoopMode];
}
- (void)saveRecordTime {
self.times ++;
//8s后隐藏提示
if (_times >= 8) {
[UIView animateWithDuration:0.3 animations:^{
_alertButton.alpha = 0;
} completion:^(BOOL finished) {
_alertButton.hidden = YES;
_alertButton.alpha = 1.0;
}];
}
//30s录制完成 停止录制
if (self.times >= 30) {
[self stopRecordIsEnterBackground:NO];
} else {
[_recordButton setTitle:[NSString stringWithFormat:@"%lds",(long)_times] forState:UIControlStateNormal];
}
}
//取消定时器
- (void)cancleTimer {
if ([_timer isValid]) {
[_timer invalidate];
_timer = nil;
}
}
#pragma mark - 懒加载方法
- (CAShapeLayer *)borderLayer {
if (!_borderLayer) {
_borderLayer = [CAShapeLayer layer];
CGMutablePathRef solidPath = CGPathCreateMutable();
_borderLayer.lineWidth = BeforeRecord_LineWidth;
_borderLayer.strokeColor = BeforeRecord_LineColor.CGColor;
_borderLayer.fillColor = [UIColor clearColor].CGColor;
CGPathAddEllipseInRect(solidPath, nil, CGRectMake(CGRectGetMinX(_recordButton.frame) - 5, CGRectGetMinY(_recordButton.frame) - 5, 0.099 * SCREEN_HEIGHT + 5*2, 0.099 * SCREEN_HEIGHT + 5*2));
_borderLayer.path = solidPath;
CGPathRelease(solidPath);
}
return _borderLayer;
}
- (CAShapeLayer *)progressLayer {
if (!_progressLayer) {
_progressLayer = [CAShapeLayer layer];
_progressLayer.frame = self.borderLayer.frame;
_progressLayer.path = [UIBezierPath bezierPathWithArcCenter:self.recordButton.center
radius:(0.099 * SCREEN_HEIGHT + 5*2)/2.0
startAngle:-M_PI_2
endAngle:-M_PI_2-2*M_PI
clockwise:NO].CGPath;
_progressLayer.fillColor = [UIColor clearColor].CGColor;
_progressLayer.lineWidth = Record_LineWidth;
_progressLayer.strokeColor = UIColorFromRGBA(0xffeb45, 1).CGColor;
_progressLayer.lineCap = kCALineCapRound;
}
return _progressLayer;
}
//动画
- (CABasicAnimation *)strokeAnimationStart {
if (!_strokeAnimationStart) {
_strokeAnimationStart = [CABasicAnimation animationWithKeyPath:@"strokeStart"];
_strokeAnimationStart.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
_strokeAnimationStart.duration = Record_TotalTime;
_strokeAnimationStart.fromValue = @1;
_strokeAnimationStart.toValue = @0;
_strokeAnimationStart.speed = 1.0;
_strokeAnimationStart.removedOnCompletion = NO;
}
return _strokeAnimationStart;
}
录制短视频的录制按钮边框计时效果相关推荐
- Android 仿微信录制短视频(不使用 FFmpeg)
转载请标明出处与作者:https://blog.csdn.net/u011133887/article/details/83654724 项目中原本就有录制短视频的功能,使用的是 # qdrzwd/V ...
- Android 仿秒拍,微信录制短视频
Android 仿秒拍,微信录制短视频 之前看了别人写的代码,但是结果自己运行时出现了这种异常.一下是自己整理后的代码: -1.首先是自定义view :MovieRecorderView.class. ...
- 【计算专业】由“打开手机 录制短视频 上传至社交账号”说计算机科学到底学什么
一件平平无奇的事情,"打开手机,录制短视频,然后上传至社交账号,然后打电话给朋友让帮忙点赞",但这整个过程涉及哪些科学技术呢?作为计算机科学或者通信工程专业的学生,是否能会想起哪些 ...
- Android仿微信录制短视频
WxRecoderVideo 简介 基于VCamera,Android仿微信录制短视频,如果喜欢请star,如果觉得有纰漏请提交issue,如果你有更好的点子可以提交pull request. 使用 ...
- 基于VCamera,仿微信录制短视频
基于VCamera,Android仿微信录制短视频,如果喜欢请star,如果觉得有纰漏请提交issue,如果你有更好的点子可以提交pull request. recoder4.gif 使用 1) 在b ...
- Android -- MediaRecorder录制短视频
一.权限 AndroidManifest.xml: <uses-permission android:name="android.permission.WRITE_EXTERNAL_S ...
- android 视频分段录制,短视频录制,分段,回删,美颜,时长限制,分辨率,码率,压缩
更新记录 1.0(2019-10-30) Android版本上线,有疑问请联系QQ37894663 平台兼容性 Android iOS √ × 原生插件通用使用流程: 购买插件,选择该插件绑定的项目. ...
- 音视频流程 - 语音/短视频 :录制(编码)和播放(解码)
-- 录制小视频: Camera -> YUV帧序列 -> YUV帧处理(镜像,缩放,旋转) -> 编码器 -> H264数据 大体上就是从摄像头输出的YUV帧经过预处理之后 ...
- android高仿微信拍摄,基于 VCamera,Android 仿微信录制短视频
调用 WechatRecoderActivity WechatRecoderActivity.launchActivity(MainActivity.this,REQ_CODE);复制代码 *在 on ...
最新文章
- Audio: 如果你愿意一层一层剥开我的心
- HTTPS(身披SSL协议的HTTP)
- [bbk4957]第69集 第8章 -性能维护 00
- python怎么将输入的数字变成列表_Python键盘输入转换为列表的实例
- 自动化测试jenkins shell命令
- 12-1-顺序文件归并-文件-第12章-《数据结构》课本源码-严蔚敏吴伟民版
- Spring Java配置:会话超时
- 苹果xr如何截屏_苹果手机自带的三种截屏技巧,你知道几个?现在知道还不迟...
- android 视频通话开启呼叫等待后,来第三方的视频通话,接通后通话时间一直显示为0,过几秒之后视频通话自己主动挂断...
- 【7005】二叉树的遍历问题2
- Exchange 2003 和 Exchange 2007最大处理器数、内存支持比较
- 在 WPF 程序中使用矢量图
- “.NET研究”理解.NET程序集的执行过程
- Windows右键菜单设置与应用技巧(转)
- popmenu 和popWindow
- arp计算机病毒解决办法,“ARP病毒的解决方案”的解决方案
- 来客电商之微信小程序怎么取名字
- 忍无可忍?英特尔执行副总裁撰文《高通的诡辩被戳穿了》指责高通
- 第二篇:STM32F7 + RT-Thread + ESP8266
- O2O模式成功案例分享 汲取精华化为己用
热门文章
- iOS UILabel UITextView自适应文本,或文本大小自适应
- 执行eclipse,迅速failed to create the java virtual machine。
- Ubuntu 和 Redhat / Fedora 服务管理命令对比表(附Fedora16新的服务管理工具systemctl )...
- 选择、分组、引用,指定匹配的位置
- Jquery实现的Tabs页签
- Apache反向代理设置【转载】
- Ajax无刷新实现图片切换特效
- .net中连接SYBASE的种种问题
- Spring源码分析【5】-Spring MVC处理流程
- Google Test(GTest)使用方法和源码解析——自动调度机制分析