CAShapeLayer的使用[2]

CAShapeLayer的使用[2]_动画

 

CAShapeLayer支持的动画类型有如下这些.

------------------------------------------------------------------------------

/* The path defining the shape to be rendered. If the path extends

 * outside the layer bounds it will not automatically be clipped to the

 * layer, only if the normal layer masking rules cause that. Defaults

 * to null. Animatable. (Note that although the path property is

 * animatable, no implicit animation will be created when the property

 * is changed.) */


@property CGPathRef path;

------------------------------------------------------------------------------

/* The color to fill the path's stroked outline, or nil for no stroking.

 * Defaults to nil. Animatable. */


@property CGColorRef strokeColor;

------------------------------------------------------------------------------

/* These values define the subregion of the path used to draw the

 * stroked outline. The values must be in the range [0,1] with zero

 * representing the start of the path and one the end. Values in

 * between zero and one are interpolated linearly along the path

 * length. strokeStart defaults to zero and strokeEnd to one. Both are

 * animatable. */


@property CGFloat strokeStart, strokeEnd;

------------------------------------------------------------------------------

/* The line width used when stroking the path. Defaults to one.

 * Animatable. */


@property CGFloat lineWidth;

------------------------------------------------------------------------------

/* The miter limit used when stroking the path. Defaults to ten.

 * Animatable. */


@property CGFloat miterLimit;

------------------------------------------------------------------------------

/* The phase of the dashing pattern applied when creating the stroke.

 * Defaults to zero. Animatable. */


@property CGFloat lineDashPhase;

------------------------------------------------------------------------------

现在来尝试path动画,结果如下:

CAShapeLayer的使用[2]_动画_02

首先用工具生成path源码:

CAShapeLayer的使用[2]_重要_03CAShapeLayer的使用[2]_CALayer_04

源码:



- (void)viewDidLoad
{
[super viewDidLoad];

// shapeLayer
CAShapeLayer *circleLayer = [CAShapeLayer layer];
circleLayer.frame = (CGRect){CGPointMake(0, 0), CGSizeMake(200, 200)};
circleLayer.position = self.view.center;
circleLayer.path = [self getStar1BezierPath].CGPath;
circleLayer.fillColor = [UIColor clearColor].CGColor;
circleLayer.strokeColor = [UIColor redColor].CGColor;
circleLayer.lineWidth = 2.f;
[self.view.layer addSublayer:circleLayer];

// 定时器
_timer = [[GCDTimer alloc] initInQueue:[GCDQueue mainQueue]];
[_timer event:^{
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;
circleLayer.path = [self getStar2BezierPath].CGPath;
[circleLayer 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;
circleLayer.path = [self getStar1BezierPath].CGPath;
[circleLayer addAnimation:circleAnim forKey:@"animateCirclePath"];
}
} timeInterval:NSEC_PER_SEC];
[_timer start];
}

-(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;
}

-(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;
}


CALayer中有一个令人抽搐的属性叫mask,据说可以做动画,官方文档上说可以:

CAShapeLayer的使用[2]_动画_05

但其属性说明中根本就没有animatable字眼.

/* A layer whose alpha channel is used as a mask to select between the

 * layer's background and the result of compositing the layer's

 * contents with its filtered background. Defaults to nil. When used as

 * a mask the layer's `compositingFilter' and `backgroundFilters'

 * properties are ignored. When setting the mask to a new layer, the

 * new layer must have a nil superlayer, otherwise the behavior is

 * undefined. */


@property(retain) CALayer *mask;

这是个bug哦:).

将CAShapeLayer当做mask做动画的效果:

CAShapeLayer的使用[2]_CALayer_06

源码:



- (void)viewDidLoad
{
[super viewDidLoad];

// shapeLayer
CAShapeLayer *circleLayer = [CAShapeLayer layer];
circleLayer.frame = (CGRect){CGPointMake(0, 0), CGSizeMake(200, 200)};
circleLayer.position = self.view.center;
circleLayer.path = [self getStar1BezierPath].CGPath;
circleLayer.fillColor = [UIColor blackColor].CGColor;
circleLayer.strokeColor = [UIColor redColor].CGColor;
circleLayer.lineWidth = 2.f;

// backgroundLayer
CALayer *layer = [CALayer layer];
layer.frame = self.view.bounds;
layer.contents = (__bridge id)([UIImage imageNamed:@"psb.jpg"].CGImage);
layer.mask = circleLayer;
[self.view.layer addSublayer:layer];

// 定时器
_timer = [[GCDTimer alloc] initInQueue:[GCDQueue mainQueue]];
[_timer event:^{
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;
circleLayer.path = [self getStar2BezierPath].CGPath;
[circleLayer 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;
circleLayer.path = [self getStar1BezierPath].CGPath;
[circleLayer addAnimation:circleAnim forKey:@"animateCirclePath"];
}
} timeInterval:NSEC_PER_SEC];
[_timer start];
}

-(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;
}

-(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;
}


 

附录:

用CAShapeLayer与贝塞尔曲线一起制作下载进度条是相当的容易的说:

CAShapeLayer的使用[2]_动画_07

//

//  RootViewController.m

//

//  Copyright (c) 2014年 Y.X. All rights reserved.

//


#import "RootViewController.h"

#import "YXGCD.h"


@interface RootViewController ()


@property (nonatomic, strong) GCDTimer *timer;


@end


@implementation RootViewController



- (void)viewDidLoad

{

    [super viewDidLoad];

    

    // 获取path

    UIBezierPath *path = [self getBezierPathWithLength:300 lineWidth:1];

    

    // shapeLayer

    CAShapeLayer *circleLayer = [CAShapeLayer layer];

    circleLayer.frame         = path.bounds;

    circleLayer.position      = self.view.center;

    circleLayer.fillColor     = [UIColor clearColor].CGColor;

    circleLayer.strokeColor   = [UIColor redColor].CGColor;

    circleLayer.path          = path.CGPath;

    circleLayer.lineWidth     = 1.f;

    [self.view.layer addSublayer:circleLayer];

    

    // 定时器

    _timer = [[GCDTimer alloc] initInQueue:[GCDQueue mainQueue]];

    [_timer event:^{


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

        

    } timeInterval:NSEC_PER_SEC];

    [_timer start];

}


-(UIBezierPath *)getBezierPathWithLength:(CGFloat)length lineWidth:(CGFloat)lineWidth

{

    //// Bezier Drawing

    UIBezierPath* bezierPath = [UIBezierPath bezierPath];

    [bezierPath moveToPoint: CGPointMake(0, 0)];

    [bezierPath addLineToPoint: CGPointMake(length, 0)];

    bezierPath.lineWidth = lineWidth;

    

    return bezierPath;

}


@end