一、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
版权声明:本文为博主原创文章,未经博主允许不得转载。