封装了一个iOS对号成功动画

请添加图片描述

基本思路其实很简单,就是通过贝塞尔曲线画出路径,然后
使用CAShapeLayer 渲染路径,然后通过strokeEnd 动画实现
路径的效果,这里注意,这个过程中过遇到过一个问题,就是
对号动画完成之后,整个对号不见了,后来经过仔细调查,发现,是自己初始化 checkLayer的时候,将strokeEnd属设置为0了,注意,虽然我们是通过"strokeEnd"设置的动画,但是我们进行动画之后,并不会真正的改变layer.strokeEnd属性的值,所以我们初始化对号layer的时候,还是要将strokeEnd设置为1
下面贴出所有代码

//
//  ViewController.m
//  LBProgressCircle
//
//  Created by mac on 2024/5/31.
//

#import "ViewController.h"

@interface ViewController ()

@property (nonatomic, strong) UIView *loadingView;

//进度圆环曲线
@property (nonatomic, strong) UIBezierPath *circlePath;
//整个圆环
@property (nonatomic, strong) CAShapeLayer *wholeCircleLayer;
//进度圆环layer
@property (nonatomic, strong) CAShapeLayer *progressLayer;
//对号圆环
@property (nonatomic, strong) CAShapeLayer *checkRoundLayer;
//对号layer
@property (nonatomic, strong) CAShapeLayer *checkLayer;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.view.backgroundColor = [UIColor lightGrayColor];
    [self.view addSubview:self.loadingView];
    [self.loadingView.layer addSublayer:self.wholeCircleLayer];
    [self.loadingView.layer addSublayer:self.progressLayer];
    [self.loadingView.layer addSublayer:self.checkLayer];
    [self.loadingView.layer addSublayer:self.checkRoundLayer];
    [self handle];
    
    // Do any additional setup after loading the view.
}

- (void)handle
{
    self.progressLayer.strokeEnd = 0;
    __block CGFloat second = 0;
    NSTimer *time = [NSTimer scheduledTimerWithTimeInterval:0.1 repeats:YES block:^(NSTimer * _Nonnull timer) {
        if (second >= 1) {
            return;
        }
        second += 0.1;
        [self updateProgress:second];
    }];
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    [self handle];
}

- (void)updateProgress:(CGFloat)progress
{
    self.progressLayer.strokeEnd = progress;
    if (progress >= 1) {
        [self showProgressCirce:NO];
        [self.checkRoundLayer addAnimation:[self animation] forKey:@"strokeEnd"];
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            self.checkLayer.hidden = NO;
            [self.checkLayer addAnimation:[self animation] forKey:@"strokeEnd"];
        });
    } else {
        self.checkLayer.hidden = YES;
        [self showProgressCirce:YES];
    }
}

- (void)showProgressCirce:(BOOL)showCircle
{
    self.checkRoundLayer.hidden = showCircle;
    self.wholeCircleLayer.hidden = !showCircle;
    self.progressLayer.hidden = !showCircle;
}

#pragma mark - lazy load

- (UIView *)loadingView
{
    if (!_loadingView) {
        _loadingView = [[UIView alloc] initWithFrame:CGRectMake(100, 100, 100, 100)];
        _loadingView.backgroundColor = [UIColor blackColor];
    }
    return _loadingView;
}

- (UIBezierPath *)circlePath
{
    if (!_circlePath) {
        _circlePath = [UIBezierPath bezierPathWithArcCenter:CGPointMake(27.5, 44) radius:19 startAngle:-M_PI_2 endAngle:-M_PI_2 + M_PI * 2 clockwise:YES];
        _circlePath.lineCapStyle = kCGLineCapRound;
        _circlePath.lineJoinStyle = kCGLineJoinRound;
    }
    return _circlePath;
}

- (CAShapeLayer *)progressLayer
{
    if (!_progressLayer) {
        _progressLayer = [[CAShapeLayer alloc] init];
        _progressLayer.path = self.circlePath.CGPath;
        _progressLayer.strokeStart = 0;
        _progressLayer.strokeEnd = 0;
        _progressLayer.strokeColor = [UIColor redColor].CGColor;
        _progressLayer.fillColor = [UIColor clearColor].CGColor;
        _progressLayer.lineWidth = 2;
    }
    return _progressLayer;
}

- (CAShapeLayer *)wholeCircleLayer
{
    if (!_wholeCircleLayer) {
        _wholeCircleLayer = [[CAShapeLayer alloc] init];
        _wholeCircleLayer.path = self.circlePath.CGPath;
        _wholeCircleLayer.strokeStart = 0;
        _wholeCircleLayer.strokeEnd = 1;
        _wholeCircleLayer.strokeColor = [[UIColor redColor] colorWithAlphaComponent:0].CGColor;
        _wholeCircleLayer.fillColor = [UIColor clearColor].CGColor;
        _wholeCircleLayer.lineWidth = 2;
    }
    return _wholeCircleLayer;
}

- (CAShapeLayer *)checkRoundLayer
{
    if (!_checkRoundLayer) {
        UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:CGPointMake(27.5, 44) radius:16 startAngle:- M_PI_2 endAngle:- M_PI_2 + M_PI * 2 clockwise:YES];
        path.lineCapStyle = kCGLineCapRound;
        path.lineJoinStyle = kCGLineJoinRound;
        _checkRoundLayer = [[CAShapeLayer alloc] init];
        _checkRoundLayer.path = path.CGPath;
        _checkRoundLayer.strokeColor = [UIColor whiteColor].CGColor;
        _checkRoundLayer.fillColor = [UIColor clearColor].CGColor;
        _checkRoundLayer.hidden = YES;
        _checkRoundLayer.lineWidth = 2;
    }
    return _checkRoundLayer;
}

- (CAShapeLayer *)checkLayer
{
    if (!_checkLayer) {
        UIBezierPath *path = [[UIBezierPath alloc] init];
        path.lineCapStyle = kCGLineCapRound;
        path.lineJoinStyle = kCGLineJoinRound;
        [path moveToPoint:CGPointMake(19, 43)];
        CGPoint pl = CGPointMake(25, 49);
        [path addLineToPoint:pl];
        CGPoint p2 = CGPointMake(36, 39);
        [path addLineToPoint:p2];
        _checkLayer = [[CAShapeLayer alloc] init];
        _checkLayer.fillColor = [UIColor clearColor].CGColor;
        //线条颜色
        _checkLayer.strokeColor = [UIColor whiteColor].CGColor;
        _checkLayer.lineWidth = 2;
        _checkLayer.path = path.CGPath;
        _checkLayer.hidden = YES;
    }
    return _checkLayer;
}

- (CABasicAnimation *)animation
{
    CABasicAnimation *checkAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
    checkAnimation.duration = 0.5;
    checkAnimation.fromValue = @(0);
    checkAnimation.toValue = @(1);
    return checkAnimation;
}

@end

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/665786.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Presto 从提交SQL到获取结果 源码详解(3)

物理执行计划 回到SqlQueryExecution.startExecution() &#xff0c;执行计划划分以后&#xff0c; // 初始化连接&#xff0c;获取Connect 元数据&#xff0c;添加会话&#xff0c;初始ConnectId metadata.beginQuery(getSession(), plan.getConnectors()); // 构建物理执行…

数据结构与算法笔记:基础篇 - 栈:如何实现浏览器的前进和后退功能?

概述 浏览器的前进、后退功能&#xff0c;你肯定很熟悉吧&#xff1f; 当依次访问完一串页面 a-b-c 之后&#xff0c;点击浏览器的后退按钮&#xff0c;就可以查看之前浏览过的页面 b 和 a。当后退到页面 a&#xff0c;点击前进按钮&#xff0c;就可以重新查看页面 b 和 c。但…

Linux编程基础 8.4:epoll工作模式

1 简介 poll机制的工作原理及流程与select类似&#xff0c;但poll可监控的进程数量不受select中第二个因素——fd_set集合容量的限制&#xff0c;用户可在程序中自行设置被监测的文件描述符集的容量&#xff0c;当然poll在阻塞模式下也采用轮询的方式监测文件描述符集&#xf…

【React】封装一个好用方便的消息框(Hooks Bootstrap 实践)

引言 以 Bootstrap 为例&#xff0c;使用模态框编写一个简单的消息框&#xff1a; import { useState } from "react"; import { Modal } from "react-bootstrap"; import Button from "react-bootstrap/Button"; import bootstrap/dist/css/b…

【LeetCode】38.外观数列

外观数列 题目描述&#xff1a; 「外观数列」是一个数位字符串序列&#xff0c;由递归公式定义&#xff1a; countAndSay(1) "1"countAndSay(n) 是 countAndSay(n-1) 的行程长度编码。 行程长度编码&#xff08;RLE&#xff09;是一种字符串压缩方法&#xff0c…

STL中list的模拟实现

目录 list模拟实现 list节点 list的push_back()函数 list的迭代器操作&#xff08;非const&#xff09; list的迭代器操作&#xff08;const&#xff09; list迭代器const 非const优化 list的insert()函数 list的erase()函数 list的pop_back() push_front() pop_front(…

数据结构:希尔排序

文章目录 前言一、排序的概念及其运用二、常见排序算法的实现 1.插入排序2.希尔排序总结 前言 排序在生活中有许多实际的运用。以下是一些例子&#xff1a; 购物清单&#xff1a;当我们去超市购物时&#xff0c;通常会列出一份购物清单。将购物清单按照需要购买的顺序排序&…

【STM32F103】HC-SR04超声波测距

【STM32F103】HC-SR04超声波测距 一、HC-SR041、工作原理2、其他参数及时序图 二、代码编写思路三、HAL配置四、代码实现五、实验结果 前言 本次实验主要实现用stm32f103HC-SR04实现超声波测距&#xff0c;将测距数值通过串口上传到上位机串口助手 一、HC-SR04 1、工作原理 (…

String类型的二维数组怎么写

今天做题遇到一个问题&#xff1a;就是需要写String类型的二维数组时&#xff0c;我蒙圈了。后来查了资料发现&#xff0c;String类型的二维数组其实是由若干个一维数组构成的。 1.先初始化一个二维数组&#xff1a;List<List<String>> list new ArrayList<&g…

登录校验及全局异常处理器

登录校验 会话技术 会话:用户打开浏览器,访问web服务器的资源,会话建立,直到有一方断开连接,会话结束.在一次会话中可以包含多次请求和响应会话跟踪:一种维护浏览器状态的方法,服务器需要识别多次请求是否来自于同一浏览器,以便在同一次会话请求间共享数据会话跟踪方案 客户端…

MT8781安卓核心板_MTK联发科Helio G99核心板规格参数

MT8781安卓核心板采用先进的台积电6纳米级芯片生产工艺&#xff0c;配备高性能Arm Cortex-A76处理器和Arm Mali G57 GPU&#xff0c;加上LPDDR4X内存和UFS 2.2存储&#xff0c;在处理速度和数据访问速度上都有着出色的表现。 MT8781还支持120Hz显示器&#xff0c;无需额外的DSC…

Transformer模型学习(1)

Transformer模型&#xff0c;它自2017年被引入以来&#xff0c;已成为处理语言任务的主流技术。Transformer模型不仅在多个语言处理任务上取得了优异的成绩&#xff0c;而且还因为它的设计极大地推动了后续模型的发展&#xff0c;如今广泛应用于聊天机器人、翻译软件和文本生成…

CS的下载+内网穿透

CS的下载 纵向渗透&#xff1a;NC 瑞士军刀菜刀是一个hyyp协议 NC是TCP NC连接后没有任何回显 先受控房 nc.exe -l -p 12345 然后攻击方 nc.exe ip port 12345 扫描端口 上传和 nc.exe 同一目录下的文件 跳板机工具和NC的实际操作以及Termite联合管理 和nc是一样的…

2024年生成式AI使用趋势报告

生成式AI技术及产品发展概况 人工智能技术奇点降临&#xff0c;搜索成为大模型技术落地的“首站” 过去几十年&#xff0c;人工智能长期鲜有突破性的发展&#xff0c;直至2022年AI大模型技术奇点的出现&#xff0c;使得AI能力发生了颠覆性的变化&#xff0c;人工智能受到了前…

cdo | 常用命令

整理一下平时经常会使用的cdo命令 如何来更改netcdf数据中的变量名呢&#xff1f; 假设我现在有一个sst月平均数据,希望将里面的变量名称sst修改为sst_new netcdf oisst_monthly { dimensions:lat 180 ;lon 360 ;time UNLIMITED ; // (476 currently)nbnds 2 ; variable…

利用“记忆化搜索“解斐波那契数

一、题目描述 求第 n 个斐波那契数。 二、 利用"记忆化搜索"解斐波那契数 什么是记忆化搜索&#xff1f;记忆化搜索就是带有备忘录的递归。 我们先来看一下使用递归来解斐波那契数的这个过程&#xff0c;假设求第5个斐波那契数F(5)。 由图可见&#xff0c;要重复计…

【mysql数据库】mycat中间件

MyCat 简介 Mycat 是数据库 中间件 。 1、 数据库中间件 中间件 是一类连接软件组件和应用的计算机软件&#xff0c; 以便于软件各部件之间的沟通 。 例子 Tomcat web 中间件 。 数据库 中间件 连接 java 应用程序和数据库 2、 为什么要用 Mycat ① Java 与数据库紧耦合 …

Halcon 光度立体 缺陷检测

一、概述 halcon——缺陷检测常用方法总结&#xff08;光度立体&#xff09; - 唯有自己强大 - 博客园 (cnblogs.com) 上周去了康耐视的新品发布会&#xff0c;我真的感觉压力山大&#xff0c;因为VM可以实现现在项目中的80% 的功能&#xff0c;感觉自己的不久就要失业了。同时…

基于Python的校园预约打印网站的实现

基于Python的校园预约打印网站的实现 开发语言:Python 数据库&#xff1a;MySQL所用到的知识&#xff1a;Django框架工具&#xff1a;pycharm、Navicat、Maven 系统功能实现 注册 新用户首先要进行注册信息填写&#xff0c;填写完成以后进行登录即可使用此网站 打印社 分别有…

vue3 前端实现导出下载pdf文件

这样的数据实现导出 yourArrayBufferOrByteArray 就是后端返回数据 // 创建Blob对象const blob new Blob([new Uint8Array(res)], { type: application/pdf })// 创建一个表示该Blob的URLconst url URL.createObjectURL(blob);// 创建一个a标签用于下载const a document.cr…