Как анимировать CoreGraphics Рисование фигуры с помощью CAKeyframeAnimation - PullRequest
7 голосов
/ 19 марта 2012

Я пытаюсь анимировать рисунок UIBeizerPath (в моем примере треугольник) в подклассе UIView. Тем не менее, все подпредставление анимируется вместо формы.

Что-то мне не хватает в анимации?

- (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 Ответ

17 голосов
/ 19 марта 2012
  • Вы создаете CAShapeLayer, но потом не делаете с ним ничего полезного.Давайте исправим это.

  • Не устанавливайте слои и анимацию в -drawRect:, потому что это строго подразумевается как время для рисования с использованием CoreGraphics или UIKit API.Вместо этого вы хотите, чтобы CAShapeLayer нарисовал треугольник - таким образом вы можете анимировать его.

  • CAKeyframeAnimation.path предназначен для чего-то совершенно другого (например, перемещение слоя вдоль пути).

  • Ваша анимация анимирует position значение слоя.Не удивительно, что он перемещает слой!Вместо этого вы хотите анимировать значение path.

  • Идея CAKeyframeAnimation заключается в том, что вы предоставляете ему массив values для установки свойства слоя.В течение времени между ключевыми кадрами он будет интерполироваться между двумя смежными ключевыми кадрами.Поэтому вам нужно указать несколько путей - по одному для каждой стороны.

  • Интерполяция произвольных путей затруднена.Интерполяция пути CA работает лучше всего, когда пути имеют одинаковое количество и вид элементов.Итак, мы удостоверяемся, что все наши пути имеют одинаковую структуру, только с некоторыми точками друг на друге.

  • Секрет анимации, а может и компьютеров вообще: вы должен быть точным в объяснении того, что вы хотите, чтобы произошло.«Я хочу анимировать рисунок каждой точки, чтобы он казался анимированным» - недостаточно информации.

Вот подкласс UIView, который я думаю делаетто, что вы просите, или, по крайней мере, близко.Для анимации подключите кнопку к действию -animate:.

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
...