录制短视频的录制按钮边框计时效果
项目增加录制短视频功能, 需一录制功能按钮, 使用贝塞尔曲线结合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;
}
相关文章:

区块链学堂:区块链引子
链客,专为开发者而生,有问必答! 此文章来自链客区块链技术问答社区,未经允许拒绝转载。 区块链学堂(1):区块链引子 相信正在看这篇文章的读者一定已经听说过区块链了,并且也相信…

Git命令文本手册
git init # 初始化本地git仓库(创建新仓库) git config --global user.name "xxx" # 配置用户名 git config --global user.email "xxxxxx.com" …

Mininet的介绍安装
Mininet的介绍 Mininet是一个强大的网络仿真平台,通过这个这个平台,我们可以很方便的模拟真实环境中的网络操作与架构。当前SDN/OpenFlow发展的如火如荼,但是在真实网络中又不可以进行相关的网络实验,自然需要一个仿真平台可以对这…
项目的简单总结一 -- 关于对贝塞尔和shapelayer结合使用的动画特效
现项目基本稳定, 要开始新的项目, 总结一二 关于对贝塞尔和shapelayer结合使用的动画特效, 在这次的项目中有几处使用到 故做了个小的demo, 记录下 效果如下: demo地址:https://github.com/wyon0313/BezierAnimation

内部区块链的优缺点
链客,专为开发者而生,有问必答! 此文章来自链客区块链技术问答社区,未经允许拒绝转载。 内部区块链的优缺点1 区块链的作用是取代可信赖的第三方,或者是在不完全相互信任的实体之间建立信任关系,如此看来…

Spring框架系列之AOP思想
微信公众号:compassblog 欢迎关注、转发,互相学习,共同进步! 有任何问题,请后台留言联系! 1、AOP概述 (1)、什么是 AOP AOP 为 Aspect Oriented Programming 的缩写,意为…

jstack 使用(转)
dump 文件里,值得关注的线程状态有:死锁,Deadlock(重点关注) 执行中,Runnable 等待资源,Waiting on condition(重点关注) 等待获取监视器,Waiting on monit…

ios TableView编辑状态多选框的修改
在- (void)layoutSubview 和 - (void)setEditing:(BOOL)editing animated:(BOOL)animated 中添加 UIImage *selectImg [UIImage imageNamed:"im_select_sign"]; UIImage *disSelectImg [UIImage imageNamed:"im_disSelect_sign"]; for (UIC…

区块链有哪些技术特征
链客,专为开发者而生,有问必答! 此文章来自链客区块链技术问答社区,未经允许拒绝转载。 区块链有哪些技术特征 在信息网络化的大背景下,当需要与不熟悉的对手方进行价值交换活动时,人们如何做才能防止不会…

《JavaEE开发的颠覆者——Spring Boot实战》是一本好书
这本书的风格非常好、每一节都是先点明这一块知识的要点,随后就手把手的做出一个最简明、但有能体现核心的实例(大多只有几个Class) 这样的书用来熟悉一门框架,实在是再好不过。转载于:https://www.cnblogs.com/nanlan2017/p/1045…

html css 布局知识概况
1、如果想设置页面居中,当设置margin属性为auto的时候,不能在设置浮动或绝对定位属性。并且一定要设置width为一个定值 2、盒子模型三维立体结构图 3、浮动布局 利用浮动可以实现横向布局,通过float来实现(left--左浮动࿰…
项目的简单总结二--可拉伸的头视图
项目总结二 tableVIew和collectionview中头视图的可拉伸放大效果 demo中只做了tableview的效果, collectionview做法一样 效果如下图: demo地址: https://github.com/wyon0313/ZoomHeaderView

浅谈区块链技术
链客,专为开发者而生,有问必答! 此文章来自链客区块链技术问答社区,未经允许拒绝转载。 浅谈区块链技术 这几天空闲的时候在网上浏览了一些区块链的技术,其实区块链只是一个技术,只不过是比特币很好的实…

IIS 7.5 去掉index.php 西数服务器
//新建web.config 加上下面代码<?xml version"1.0"?> <configuration> <system.webServer><rewrite><rules><rule name"OrgPage" stopProcessing"true"><match url"^(.*)$" /><condit…

bzoj1927: [Sdoi2010]星际竞速
跟上一题几乎一样。。。 #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<queue> using namespace std; #define rep(i,n) for(int i1;i<n;i) #define clr(x,c) memset(x,c,sizeof(x)) #define op() cl…

在cell中取得UITableView所在的ViewController对象
原来碰到这个问题一般会将控制器传进cell中, 或者将cell要做的响应事件回调到控制器去处理, 前段时间找到一种方法觉得很不错 - (UIViewController *)getTableViewSuperViewController { for (UIView* next [self superview]; next; next next.superview) { UI…

区块链当前现状
链客,专为开发者而生,有问必答! 此文章来自链客区块链技术问答社区,未经允许拒绝转载。 区块链是分布式账本技术,用于记录交易数据,具有不可篡改性、完整分布性、可追溯性等技术优势,应用包括…

MVC 4.0 Razor模板引擎 @Html.RenderPartial 与 @Html.RenderAction 区别
近来在学习MVC 4.0,设置布局全局网页的页脚,使用了Razor语法 {Html.RenderPartial("Footer", Model.FooterData);} 但是并不理解Html帮助器方法Html.RenderPartial。 先来介绍一下Html.RenderPartial用法。 Html.RenderPartial在Asp.net Mvc中…

iOS 图片处理-利用GPUImage 磨皮和美白图片
项目中要求处理图片, 简单记录一下美白和磨皮过程 (其中GPUImage还有美颜滤镜, 使用方式基本一样) //磨皮 - (void)editPhotoByBilateralWithLevel:(CGFloat)level { GPUImagePicture *pic [[GPUImagePicture alloc] initWithImage:image]; // 磨皮滤镜…

linux下编译php扩展
1 在pecl.php.net搜索你需要的php扩展 2 在解压后的扩展目录运行phpize 3 执行编译./configure --with-php-config/usr/local/php/bin/php-config 4 修改php/lib/php.ini文件 加上这句话extention扩展.so的绝对路径转载于:https://www.cnblogs.com/wyqn/p/8493456.html

区块链技术原理
链客,专为开发者而生,有问必答! 此文章来自链客区块链技术问答社区,未经允许拒绝转载。 以比特币的区块链为例,你可以把区块链想象成一个比特币的公共账本,这个账本: 1.存放在互联网的各个比…

Spring之事务管理配置
1. 基于注解的事务配置 1. 在需要添加事务的方法上加上Transactional注解2. Spring的配置文件中配置事务管理器1 <!-- 添加事务管理器组件DataSourceTransactionManager -->2 <bean id"transactionManager"3 class"org.springframewor…

iOS 图片处理-图片旋转和裁剪
项目中要求处理图片, 简单记录一下图片旋转和裁剪过程 /** 将图片旋转弧度radians */- (UIImage *)imageRotatedByRadians:(CGFloat)radians{ // calculate the size of the rotated views containing box for our drawing space UIView *rotatedViewBox [[UIView alloc…

ThinkPHP 3.1.2 视图 1
一、模板的使用 (重点)a、规则模板文件夹下[TPL]/[分组文件夹/][模板主题文件夹/]和模块名同名的文件夹[Index]/和方法名同名的文件[index].html(.tpl)更换模板文件的后缀名(修改配置文件)TMPL_TEMP…

mysql事务处理用法与实例详解
MySQL的事务支持不是绑定在MySQL服务器本身,而是与存储引擎相关1.MyISAM:不支持事务,用于只读程序提高性能 2.InnoDB:支持ACID事务、行级锁、并发 3.Berkeley DB:支持事务一个事务是一个连续的一组数据库操作ÿ…

C++ 类的内存分布
C类内存分布 转自:http://www.cnblogs.com/jerry19880126/p/3616999.html先写下总结,通过总结下面的例子,你就会明白总结了。下面总结一下: 1、虚基类指针和虚函数指针是可以继承的 2. 虚函数指针来源于父类或者自己是第一个声明虚…

iOS 关于手机权限的检查与获取
手机通讯录权限: /** * 检测权限并作响应的操作 */ - (void)checkAuthorizationStatus:(UISwitch *)sender { switch (ABAddressBookGetAuthorizationStatus()) { case kABAuthorizationStatusAuthorized: //存在权限 //获取通讯…

也谈谈区块链技术
链客,专为开发者而生,有问必答! 此文章来自区块链社区,未经允许拒绝转载。 现在区块链技术很火,而且几乎被上升到了一个“革命性”的高度,很多股票居然都因为沾了点区块链变得炙手可热。其实这玩意没有这么…

nyoj——297(期望)
GoroSort 时间限制:3000 ms | 内存限制:65535 KB难度:4描述Goro has 4 arms. Goro is very strong. You dont mess with Goro. Goro needs to sort an array of N different integers. Algorithms are not Goros strength; strength is Gor…

js ajax调用请求
<pre name"code" class"html"> function getAppList(env){var data {};data.env env;var successfn function(jdata){$(".deploy_list").html("");_HTML "<tr><th>发布清单</th></tr>";$…