CAShapeLayer实现圆形进度条效果

一、CAShapeLayer简介:

1、CAShapeLayer继承至CALayer,可以使用CALayer的所有属性值

2、CAShapeLayer需要与贝塞尔曲线配合使用才有意义

3、使用CAShapeLayer与贝塞尔曲线可以实现不在view的drawRect方法中画出一些想要的图形

4、CAShapeLayer属于CoreAnimation框架,其动画渲染直接提交到手机的GPU当中,相较于view的drawRect方法使用CPU渲染而言,其效率极高,能大大优化内存使用情况

五角星动画

#import "ViewController.h"

@interface
ViewController ()

@property (nonatomic,
strong) NSTimer      *timer;

@property (nonatomic,
strong) CAShapeLayer *shapeLayer;

@end

@implementation ViewController

- (void)viewDidLoad {

[super
viewDidLoad];

//
创建shapeLayer

_shapeLayer = [CAShapeLayer
layer];

_shapeLayer.frame         = (CGRect){CGPointMake(0,
0), CGSizeMake(200,
200)};

_shapeLayer.position      =
self.view.center;

_shapeLayer.path          = [self
getStar1BezierPath].CGPath;

_shapeLayer.fillColor     = [UIColor
clearColor].CGColor;

_shapeLayer.strokeColor   = [UIColor
redColor].CGColor;

_shapeLayer.lineWidth     =
2.f;

[self.view.layer
addSublayer:_shapeLayer];

//
创建定时器

_timer = [NSTimer
scheduledTimerWithTimeInterval:1.f

target:self

selector:@selector(pathAnimation)

userInfo:nil

repeats:YES];

}

/**

*  执行path的动画

*/

- (void)pathAnimation {

static int i =
0;

if (i++ % 2 ==
0) {

CABasicAnimation *circleAnim = [CABasicAnimation
animationWithKeyPath:@"path"];

circleAnim.removedOnCompletion =
NO;

circleAnim.duration            =
1;

circleAnim.fromValue           = (__bridge
id)[self
getStar1BezierPath].CGPath;

circleAnim.toValue             = (__bridge
id)[self
getStar2BezierPath].CGPath;

_shapeLayer.path               = [self
getStar2BezierPath].CGPath;

[_shapeLayer
addAnimation:circleAnim
forKey:@"animateCirclePath"];

}
else {

CABasicAnimation *circleAnim = [CABasicAnimation
animationWithKeyPath:@"path"];

circleAnim.removedOnCompletion =
NO;

circleAnim.duration            =
1;

circleAnim.fromValue           = (__bridge
id)[self
getStar2BezierPath].CGPath;

circleAnim.toValue             = (__bridge
id)[self
getStar1BezierPath].CGPath;

_shapeLayer.path               = [self
getStar1BezierPath].CGPath;

[_shapeLayer
addAnimation:circleAnim
forKey:@"animateCirclePath"];

}

}

/**

*  贝塞尔曲线1

*

*  @return
贝塞尔曲线

*/

-(UIBezierPath *)getStar1BezierPath {

//// Star Drawing

UIBezierPath* starPath = [UIBezierPath
bezierPath];

[starPath
moveToPoint: CGPointMake(22.5,
2.5)];

[starPath addLineToPoint:
CGPointMake(28.32,
14.49)];

[starPath addLineToPoint:
CGPointMake(41.52,
16.32)];

[starPath addLineToPoint:
CGPointMake(31.92,
25.56)];

[starPath addLineToPoint:
CGPointMake(34.26,
38.68)];

[starPath addLineToPoint:
CGPointMake(22.5,
32.4)];

[starPath addLineToPoint:
CGPointMake(10.74,
38.68)];

[starPath addLineToPoint:
CGPointMake(13.08,
25.56)];

[starPath addLineToPoint:
CGPointMake(3.48,
16.32)];

[starPath addLineToPoint:
CGPointMake(16.68,
14.49)];

[starPath
closePath];

return starPath;

}

/**

*  贝塞尔曲线2

*

*  @return
贝塞尔曲线

*/

-(UIBezierPath *)getStar2BezierPath {

//// Star Drawing

UIBezierPath* starPath = [UIBezierPath
bezierPath];

[starPath
moveToPoint: CGPointMake(22.5,
2.5)];

[starPath addLineToPoint:
CGPointMake(32.15,
9.21)];

[starPath addLineToPoint:
CGPointMake(41.52,
16.32)];

[starPath addLineToPoint:
CGPointMake(38.12,
27.57)];

[starPath addLineToPoint:
CGPointMake(34.26,
38.68)];

[starPath addLineToPoint:
CGPointMake(22.5,
38.92)];

[starPath addLineToPoint:
CGPointMake(10.74,
38.68)];

[starPath addLineToPoint:
CGPointMake(6.88,
27.57)];

[starPath addLineToPoint:
CGPointMake(3.48,
16.32)];

[starPath addLineToPoint:
CGPointMake(12.85,
9.21)];

[starPath
closePath];

return starPath;

}

@end

二、贝塞尔曲线与CAShapeLayer的关系

1、CAShapeLayer中有Shape这个单词,顾名思义,它需要一个形状才能生效

2、贝塞尔曲线可以创建基于矢量的路径

3、贝塞尔曲线给CAShapeLayer提供路径,CAShapeLayer在提供的路径中进行渲染,路径会闭环,所以路径绘制出了Shape

4、用于CAShapeLayer的贝塞尔曲线作为path,其path是一个首尾相接的闭环的曲线,即使该贝塞尔曲线不是一个闭环的曲线

注意:shape的frame 要大于BezierPath的frame.BezierPath不会因为share的frame而拉升,否则BezierPath截断

- (void)viewDidLoad {

[super
viewDidLoad];

//
创建椭圆形贝塞尔曲线

UIBezierPath *oval = [UIBezierPath
bezierPathWithOvalInRect:CGRectMake(0,
0, 200,
100)];

//
创建矩形贝塞尔曲线

UIBezierPath *rect = [UIBezierPath
bezierPathWithRect:CGRectMake(0,
0, 200,
100)];

//
创建圆形贝塞尔曲线

UIBezierPath *circle = [UIBezierPath
bezierPathWithOvalInRect:CGRectMake(0,
0, 100,
100)];

//
创建CAShapeLayer

CAShapeLayer *shape = [CAShapeLayer
layer];

shape.frame         =
CGRectMake(0,
0, 200,
50);

shape.position      =
self.view.center;

//
显示CAShapeLayer的边界

shape.borderWidth   =
1.f;

//
禁止内容显示超出CAShapeLayer的frame值

shape.masksToBounds =
YES;

//
修改贝塞尔曲线的填充颜色

shape.fillColor     = [UIColor
redColor].CGColor;

//
建立贝塞尔曲线与CAShapeLayer之间的关联

shape.path = circle.CGPath;

//
添加并显示

[self.view.layer
addSublayer:shape];

}

三、StrokeStart与StrokeEnd动画

1、将ShapeLayer的fillColor设置成透明背景

2、设置线条的宽度(lineWidth)的值

3、设置线条的颜色

4、将strokeStart值设定成0,然后让strokeEnd的值变化触发隐式动画

@interface
ViewController ()

@property (nonatomic,
strong) NSTimer      *timer;     
// 定时器

@property (nonatomic,
strong) CAShapeLayer *shapeLayer;
// 形状layer

@end

@implementation ViewController

- (void)viewDidLoad {

[super
viewDidLoad];

//
设置背景色

self.view.backgroundColor = [UIColor
colorWithRed:0.878
green:0.878
blue:0.878
alpha:1];

//
创建椭圆形贝塞尔曲线

UIBezierPath *oval        = [UIBezierPath
bezierPathWithOvalInRect:CGRectMake(0,
0, 100,
100)];

//
创建CAShapeLayer

_shapeLayer               = [CAShapeLayer
layer];

_shapeLayer.frame         =
CGRectMake(0,
0, 100,
100);

_shapeLayer.position      =
self.view.center;

//
修改CAShapeLayer的线条相关值

_shapeLayer.fillColor     = [UIColor
clearColor].CGColor;

_shapeLayer.strokeColor   = [UIColor
redColor].CGColor;

_shapeLayer.lineWidth     =
2.f;

_shapeLayer.strokeStart   =
0.f;

_shapeLayer.strokeEnd     =
0.f;

//
建立贝塞尔曲线与CAShapeLayer之间的关联

_shapeLayer.path          = oval.CGPath;

//
添加并显示

[self.view.layer
addSublayer:_shapeLayer];

//
创建定时器

_timer = [NSTimer
scheduledTimerWithTimeInterval:1.f

target:self

selector:@selector(animationEventTypeTwo)

userInfo:nil

repeats:YES];

}

/**

*  动画效果1

*/

- (void)animationEventTypeOne {

//
执行隐式动画

_shapeLayer.strokeEnd =
arc4random() % 100 /
100.f;

}

/**

*  动画效果2

*/

- (void)animationEventTypeTwo {

CGFloat valueOne =
arc4random() % 100 /
100.f;

CGFloat valueTwo =
arc4random() % 100 /
100.f;

// storkeStar 与storkeEnd同时赋值,strokeStart要小于strokeEnd的值

//
执行隐式动画

_shapeLayer.strokeStart = valueOne < valueTwo ? valueOne : valueTwo;

_shapeLayer.strokeEnd   = valueOne > valueTwo ? valueOne : valueTwo;

}

@end

四、用CAShapeLayer实现圆形进度条效果

1、确定需要设定的参数

2、实现细节

3、进行测试

@interface CircleView :
UIView

@property (nonatomic,
assign) CGFloat  startValue;
// 起始值(0~1)

@property (nonatomic,
assign) CGFloat  lineWidth; 
// 线宽(>0)

@property (nonatomic,
strong) UIColor *lineColor; 
// 线条颜色

@property (nonatomic,
assign) CGFloat  value;     
// 变化的值

@end

#import "CircleView.h"

@interface CircleView ()

@property (nonatomic,
strong) CAShapeLayer *shapeLayer;

@end

@implementation CircleView

- (instancetype)initWithFrame:(CGRect)frame {

self = [super
initWithFrame:frame];

if (self) {

//
创建出CAShapeLayer

_shapeLayer       = [CAShapeLayer
layer];

_shapeLayer.frame =
self.bounds;

//
创建出贝塞尔曲线

UIBezierPath *path = [UIBezierPath
bezierPathWithOvalInRect:self.bounds];

//
贝塞尔曲线与CAShapeLayer产生关联

_shapeLayer.path = path.CGPath;

// 基本配置

_shapeLayer.fillColor   = [UIColor
clearColor].CGColor;

_shapeLayer.lineWidth   =
1.f;

_shapeLayer.strokeColor = [UIColor
redColor].CGColor;

_shapeLayer.strokeEnd   =
0.f;

//
添加到当前view

[self.layer
addSublayer:_shapeLayer];

}

return
self;

}

@synthesize startValue =
_startValue;

- (void)setStartValue:(CGFloat)startValue {

_startValue           = startValue;

_shapeLayer.strokeEnd = startValue;

}

- (CGFloat)startValue {

return
_startValue;

}

@synthesize lineWidth =
_lineWidth;

- (void)setLineWidth:(CGFloat)lineWidth {

_lineWidth            = lineWidth;

_shapeLayer.lineWidth = lineWidth;

}

- (CGFloat)lineWidth {

return
_lineWidth;

}

@synthesize lineColor =
_lineColor;

- (void)setLineColor:(UIColor *)lineColor {

_lineColor              = lineColor;

_shapeLayer.strokeColor = lineColor.CGColor;

}

- (UIColor *)lineColor {

return
_lineColor;

}

@synthesize value = _value;

- (void)setValue:(CGFloat)value {

_value                = value;

_shapeLayer.strokeEnd = value;

}

- (CGFloat)value {

return _value;

}

@end

#import "CircleView.h"

@interface
ViewController ()

{

CircleView *circle;

}

@end

@implementation ViewController

- (void)viewDidLoad {

[super
viewDidLoad];

circle             = [[CircleView
alloc] initWithFrame:CGRectMake(0,
0, 200,
200)];

circle.center      =
self.view.center;

circle.startValue  =
0.5;

circle.lineWidth   =
3.f;

circle.lineColor   = [UIColor
grayColor];

[self.view
addSubview:circle];

[self
performSelector:@selector(delayAnimation)

withObject:nil

afterDelay:3.f];

}

- (void)delayAnimation {

circle.value =
1.f;

}

@end

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-01 02:36:11

CAShapeLayer实现圆形进度条效果的相关文章

canvas 绘制圆形进度条

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>canvas 圆形进度条效果</title> <style> *{margin:0;padding:0;} body{text-align:center;background-color:#000;} </style> </he

基于CAShapeLayer和贝塞尔曲线的圆形进度条动画【装载】

初次接触CAShapeLayer和贝塞尔曲线,看了下极客学院的视频.对初学者来说感觉还不错.今天来说一个通过CAShapeLayer和贝塞尔曲线搭配的方法,创建的简单的圆形进度条的教程先简单的介绍下CAShapeLayer1,CAShapeLayer继承自CALayer,可使用CALayer的所有属性2,CAShapeLayer需要和贝塞尔曲线配合使用才有意义.Shape:形状贝塞尔曲线可以为其提供形状,而单独使用CAShapeLayer是没有任何意义的.3,使用CAShapeLayer与贝塞尔

一个不是那么优美的圆形进度条续(基本还原原应用里面的效果)

之前帮别人写了一个不是那么优美的圆形进度条,效果图大家也看过了.但是后某人不满意,说原应用是倒计时时间最后5s,才开始显示数字的,同时转完一圈需要的时间只能是30s左右.然后我掐时间看了一下虽然总时间设置的是30s,但是总共转完一圈却耗费了50多秒的样子. 问题出来了: 1. 转圈总时间30s不正确 2. 数字显示时间不正确 3. 数字1的动画没原应用的好(2144手机令牌) 花了一个小时搞了一下,忍不住终于射出来了什么东西,解决了上面的3个问题(请看1从有到无):国际惯例效果图先行,先看下改善

android自定义圆形进度条,实现动态画圆效果

自定义圆形进度条效果图如下:应用场景如动态显示分数等. view的自定义属性如下attr.xml <?xml version="1.0" encoding="UTF-8"?> <resources> <declare-styleable name="ArcProgressbar">         <!-- 圆环起始角度-->         <attr name="startAng

用HTML、CSS、JS制作圆形进度条(无动画效果)

逻辑 1.首先有一个圆:蓝色的纯净的圆,效果: 2.再来两个半圆,左边一个,右边一个将此蓝色的圆盖住,效果: 此时将右半圆旋转60°,就会漏出底圆,效果: 然后我们再用一个比底圆小的圆去覆盖这个大圆就可以出进度条效果了 代码: <style>     /*支持IE9及以上*/    .circle-bar {margin: 20px; font-size:200px; width: 1em; height: 1em; position: relative;  background-color:

Android自定义View——圆形进度条式按钮

介绍 今天上班的时候有个哥们问我怎么去实现一个按钮式的进度条,先来看看他需要实现的效果图. 和普通的圆形进度条类似,只是中间的地方有两个状态表示,未开始,暂停状态.而且他说圆形进度的功能已经实现了.那么我们只需要对中间的两个状态做处理就行了. 先来看看实现的效果图: 上面说了我们只需要处理中间状态的变化就可以了,对于进度的处理直接使用了弘洋文章中实现: http://blog.csdn.net/lmj623565791/article/details/43371299 下面开始具体实现. 具体实

Android 高手进阶之自定义View,自定义属性(带进度的圆形进度条)

转载请注明地址:http://blog.csdn.net/xiaanming/article/details/10298163 很多的时候,系统自带的View满足不了我们功能的需求,那么我们就需要自己来自定义一个能满足我们需求的View,自定义View我们需要先继承View,添加类的构造方法,重写父类View的一些方法,例如onDraw,为了我们自定义的View在一个项目中能够重用,有时候我们需要自定义其属性,举个很简单的例子,我在项目中的多个界面使用我自定义的View,每个界面该自定义View

WPF 实现圆形进度条

项目中用到圆形进度条,首先就想到使用 ProgressBar 扩展一个,在园子里找到 迷途的小榔头 给出的思路和部分代码,自己加以实现.在此感谢 迷途的小榔头! 进度小于60显示红色,大于60则显示绿色.效果如下: 基本思路: 本质上是一个进度条,只是外观有别于矩形进度条,所以需要修改ProgressBar的ControlTemplate. 进度条部分实际是一个扇形,用WPF动态绘出(原理参考迷途的小榔头讲解). 要将进度条的值(Value依赖属性)转换为进度条,需要一个Converter. 根

HTML5动画(二):Canvas 实现圆形进度条并显示数字百分比

实现效果 1.首先创建html代码 <canvas id="canvas" width="500" height="500" style="background:#000;"></canvas> 2.创建canvas环境 var canvas = document.getElementById('canvas'), //获取canvas元素 context = canvas.getContext('2d