使用CoreAnimation制作形状动画

15

我正在尝试使用核心动画和绘制实现一个简单形状的动画效果。这个形状由3条线和一条贝塞尔曲线组成。为了显示曲线控制点,还会绘制一条红线。

alt text http://img.skitch.com/20091119-1ufar435jdq7nwh8pid5cb6kmm.jpg

我的主控制器只是添加了这个子视图,并在touchesEnd时调用adjustWave方法。下面是我用于绘制形状的代码。你会发现这个类只有一个属性,cp1x(即贝塞尔曲线控制点1的x值)。我想要对它进行动画处理,但这只是一个愚蠢的尝试...

- (void)drawRect:(CGRect)rect {
    float cp1y = 230.0f;
    float cp2x = 100.0f;
    float cp2y = 120.0f;

    CGContextRef ctx = UIGraphicsGetCurrentContext(); 
    CGContextClearRect(ctx, rect);

    CGMutablePathRef path = CGPathCreateMutable(); 
    CGPathMoveToPoint(path, NULL, 10.0f, 200.0f); 
    CGPathAddCurveToPoint (path, NULL, cp1x, cp1y, cp2x, cp2y, 300.0f, 200.0f);
    CGPathAddLineToPoint(path, NULL, 300.0f, 300.0f); 
    CGPathAddLineToPoint(path, NULL, 10.0f, 300.0f); 
    CGPathCloseSubpath(path); 
    CGContextSetFillColorWithColor(ctx, [UIColor blueColor].CGColor); 
    CGContextAddPath(ctx, path); 
    CGContextFillPath(ctx);

    // Drawing a line from control points 1 and 2
    CGContextBeginPath(ctx);
    CGContextSetRGBStrokeColor(ctx,1,0,0,1);
    CGMutablePathRef cp1 = CGPathCreateMutable(); 
    CGPathMoveToPoint(cp1, NULL, cp1x, cp1y); 
    CGPathAddLineToPoint(cp1, NULL, cp2x, cp2y); 
    CGPathCloseSubpath(cp1); 
    CGContextAddPath(ctx, cp1); 
    CGContextStrokePath(ctx);
}

- (void)adjustWave {
    [UIView beginAnimations:@"movement" context:nil]; 
    [UIView setAnimationDelegate:self]; 
    [UIView setAnimationWillStartSelector:@selector(didStart:context:)]; 
    [UIView setAnimationDidStopSelector:@selector(didStop:finished:context:)]; 
    [UIView setAnimationCurve:UIViewAnimationCurveEaseIn];
    [UIView setAnimationDuration:3.0f]; 
    [UIView setAnimationRepeatCount:3]; 
    [UIView setAnimationRepeatAutoreverses:YES]; 
    cp1x = cp1x + 20.0f;
    [UIView commitAnimations];
}

形状没有改变。相反,如果我去掉CA代码并在最后一个方法中添加一个简单的`[self setNeedsDisplay]`,则形状会发生变化,但显然没有了CA。你能帮助我吗?我确定我在这里犯了一个非常基本的错误...谢谢您提前。


正如Brad所说,您可以使用CAShapeLayer类通过构建CABasicAnimation或CAKeyframeAnimation并通过“path”属性进行动画处理来动画化任意形状。如果您想查看示例代码,我写了一篇关于此类的文章。http://bit.ly/shapelayer - Joe Ricioppo
2个回答

18
如果您正在为iPhone OS 3.x(或Snow Leopard)编写此代码,则新的CAShapeLayer类应该可以让您轻松地执行此类动画。 如果您有一个保持相同控制点数量的路径(就像在您的情况下),则可以将该路径设置为CAShapeLayer,然后将路径属性从起始值动画到最终路径。 核心动画会执行路径中控制点的适当插值,以在这两个状态之间对其进行动画处理(如果使用CAKeyframeAnimation,则还可以进行更多操作)。

请注意,这是一个图层,因此您需要将其添加为UIView的子图层。 另外,我认为路径属性不会隐式动画化,因此您可能需要手动创建CABasicAnimation来将形状从路径1动画到路径2。

编辑(11/21/2009):Joe Ricioppo在这里撰写了有关CAShapeLayer的详细介绍,其中包括一些展示这些类型动画的视频。


CAShapeLayer在iPhone OS 3.x中非常有Bug。 - dontWatchMyProfile
@mystify - 以什么方式?我用它表现得相当好,但你需要记住在路径中有相同数量的起始和结束控制点,否则结果是未定义的。 - Brad Larson

-1

您无法使用CA对形状进行动画处理。您只能在CA中动画处理层属性,而不能自定义属性。

CA之所以快速,是因为它无需回调到您的代码来执行动画操作。如果您考虑其实现方式,它基本上只是一个线程运行GL基元操作,根据CALayer框架和内容执行操作。

CA动画是一组指令,供CA在后台线程上运行,启动并忘记(加上在动画完成时的回调),而不是回调到您的代码。

要对图层的内容进行动画处理,需要CA在每个帧上回调您进行绘制,或让您指示CA如何进行绘制。这两种情况都不会发生。


我想我在这里还有很多东西要学习 :) 无论如何,我并不真的关心我上面展示的代码,它只是一个概念证明。是否有其他类似的方法可以使用CA完成同样的事情?或者我应该将CA保持原样并调用setNeedDisplay? - nutsmuggler
setNeedsDisplay是一种方式,openGL是另一种方式。我不认为你可以使用CA实现。 - duncanwilcox
1
实际上,你可以使用CAShapeLayer类和动画化'path'属性来实现形状的动画效果。 - Joe Ricioppo
1
Joe实际上有一篇很好的关于CAShapeLayer的文章(附带视频):http://tumbljack.com/post/179975074/complex-interpolation-with-cashapelayer-free - Brad Larson
动画化路径可能会解决上面的特定图像,尽管nutsmuggler说“上面显示的代码只是一个概念证明”。动画化路径绝不是通用的绘图动画。但我确实没有提到CAShapeLayer,对此我很抱歉。 - duncanwilcox

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接