How to Animate CoreGraphics Drawing of Shape Using CAKeyframeAnimation

ⅰ亾dé卋堺 提交于 2020-01-10 10:51:03

问题


I am trying to animate the drawing of a UIBeizerPath (in my example a triangle) in a UIView subclass. However, the entire subview is animating instead of the shape.

Is there something I am missing with the animation?

- (void)drawRect:(CGRect)rect {

   CAShapeLayer *drawLayer = [CAShapeLayer layer];

   drawLayer.frame           = CGRectMake(0, 0, 100, 100);
   drawLayer.strokeColor     = [UIColor greenColor].CGColor;
   drawLayer.lineWidth       = 4.0;

   [self.layer addSublayer:drawLayer];

   UIBezierPath *path = [UIBezierPath bezierPath];

  [path moveToPoint:CGPointMake(0,0)];
  [path addLineToPoint:CGPointMake(50,100)];
  [path addLineToPoint:CGPointMake(100,0)];
  [path closePath];

  CGPoint center = [self convertPoint:self.center fromView:nil];

  [path applyTransform:CGAffineTransformMakeTranslation(center.x, center.y)];

  [[UIColor redColor] set];

  [path fill];

  [[UIColor blueColor] setStroke];

  path.lineWidth = 3.0f;

  [path stroke];

  CAKeyframeAnimation *pathAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"];

  pathAnimation.duration        = 4.0f;
  pathAnimation.path            = path.CGPath;
  pathAnimation.calculationMode = kCAAnimationLinear;

  [drawLayer addAnimation:pathAnimation forKey:@"position"];
}

回答1:


  • You are creating a CAShapeLayer, but then not doing anything useful with it. Let's fix that.

  • Don't set up layers and animations in -drawRect:, because that's strictly meant as a time to do drawing using the CoreGraphics or UIKit APIs. Instead, you want the CAShapeLayer to draw the triangle -- that way you can animate it.

  • CAKeyframeAnimation.path is meant for something completely different (e.g. moving a layer along a path).

  • Your animation is animating the position value of the layer. No surprise that it moves the layer! You want to animate the path value instead.

  • The idea behind CAKeyframeAnimation is that you provide it an array of values to set the layer's property to. During the time between keyframes, it will interpolate between the two adjacent keyframes. So you need to give it several paths -- one for each side.

  • Interpolating arbitrary paths is difficult. CA's path interpolation works best when the paths have the same same number and kind of elements. So, we make sure all our paths have the same structure, just with some points on top of each other.

  • The secret to animation, and maybe to computers in general: you must be precise in explaining what you want to happen. "I want to animate the drawing of each point, so it appears to be animated" is not nearly enough information.

Here's a UIView subclass that I think does what you're asking for, or at least close. To animate, hook a button up to the -animate: action.

SPAnimatedShapeView.h:

#import <UIKit/UIKit.h>

@interface SPAnimatedShapeView : UIView

- (IBAction)animate:(id)sender;

@end

SPAnimatedShapeView.m:

#import "SPAnimatedShapeView.h"
#import <QuartzCore/QuartzCore.h>

@interface SPAnimatedShapeView ()
@property (nonatomic, retain)   CAShapeLayer*   shapeLayer;
@end

@implementation SPAnimatedShapeView

@synthesize shapeLayer = _shapeLayer;

- (void)dealloc
{
    [_shapeLayer release];
    [super dealloc];
}

- (void)layoutSubviews
{
    if (!self.shapeLayer)
    {
        self.shapeLayer = [[[CAShapeLayer alloc] init] autorelease];
        self.shapeLayer.bounds = CGRectMake(0, 0, 100, 100);     // layer is 100x100 in size
        self.shapeLayer.position = self.center;                  // and is centered in the view
        self.shapeLayer.strokeColor = [UIColor blueColor].CGColor;
        self.shapeLayer.fillColor = [UIColor redColor].CGColor;
        self.shapeLayer.lineWidth = 3.f;

        [self.layer addSublayer:self.shapeLayer];
    }
}

- (IBAction)animate:(id)sender
{
    UIBezierPath* path0 = [UIBezierPath bezierPath];
    [path0 moveToPoint:CGPointZero];
    [path0 addLineToPoint:CGPointZero];
    [path0 addLineToPoint:CGPointZero];
    [path0 addLineToPoint:CGPointZero];

    UIBezierPath* path1 = [UIBezierPath bezierPath];
    [path1 moveToPoint:CGPointZero];
    [path1 addLineToPoint:CGPointMake(50,100)];
    [path1 addLineToPoint:CGPointMake(50,100)];
    [path1 addLineToPoint:CGPointMake(50,100)];

    UIBezierPath* path2 = [UIBezierPath bezierPath];
    [path2 moveToPoint:CGPointZero];
    [path2 addLineToPoint:CGPointMake(50,100)];
    [path2 addLineToPoint:CGPointMake(100,0)];
    [path2 addLineToPoint:CGPointMake(100,0)];

    UIBezierPath* path3 = [UIBezierPath bezierPath];
    [path3 moveToPoint:CGPointZero];
    [path3 addLineToPoint:CGPointMake(50,100)];
    [path3 addLineToPoint:CGPointMake(100,0)];
    [path3 addLineToPoint:CGPointZero];

    CAKeyframeAnimation* animation = [CAKeyframeAnimation animationWithKeyPath:@"path"];    
    animation.duration = 4.0f;
    animation.values = [NSArray arrayWithObjects:(id)path0.CGPath, (id)path1.CGPath, (id)path2.CGPath, (id)path3.CGPath, nil];
    [self.shapeLayer addAnimation:animation forKey:nil];
}

@end


来源:https://stackoverflow.com/questions/9762236/how-to-animate-coregraphics-drawing-of-shape-using-cakeyframeanimation

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!