Tuy*_*yen 4 iphone core-animation objective-c
您知道如何在MKMapView中创建像Blue Marble drop User-Location这样的动画吗?
Sam*_*Sam 11
虽然我不确定Apple如何实现这种效果,但这对我来说是一个使用CoreAnimation和自定义动画属性的绝佳机会. 这篇文章提供了一些关于这个主题的好背景.我假设通过"Blue Marble drop"动画你指的是以下顺序:
虽然这可能会略微简化这个过程,但我认为它是一个很好的起点,可以相对轻松地添加更复杂/更详细的功能(即较小的黑色圆形脉冲,因为较大的圆形会聚在其上.)
我们需要的第一件事是自定义CALayer子类,它具有我们外部大的浅蓝色圆圈半径的自定义属性:
#import <QuartzCore/QuartzCore.h>
@interface CustomLayer : CALayer
@property (nonatomic, assign) CGFloat circleRadius;
@end
Run Code Online (Sandbox Code Playgroud)
和实施:
#import "CustomLayer.h"
@implementation CustomLayer
@dynamic circleRadius; // Linked post tells us to let CA implement our accessors for us.
// Whether this is necessary or not is unclear to me and one
// commenter on the linked post claims success only when using
// @synthesize for the animatable property.
+ (BOOL)needsDisplayForKey:(NSString*)key {
// Let our layer know it has to redraw when circleRadius is changed
if ([key isEqualToString:@"circleRadius"]) {
return YES;
} else {
return [super needsDisplayForKey:key];
}
}
- (void)drawInContext:(CGContextRef)ctx {
// This call is probably unnecessary as super's implementation does nothing
[super drawInContext:ctx];
CGRect rect = CGContextGetClipBoundingBox(ctx);
// Fill the circle with a light blue
CGContextSetRGBFillColor(ctx, 0, 0, 255, 0.1);
// Stoke a dark blue border
CGContextSetRGBStrokeColor(ctx, 0, 0, 255, 0.5);
// Construct a CGMutablePath to draw the light blue circle
CGMutablePathRef path = CGPathCreateMutable();
CGPathAddArc(path, NULL, rect.size.width / 2,
rect.size.height / 2,
self.circleRadius, 0, 2 * M_PI, NO);
// Fill the circle
CGContextAddPath(ctx, path);
CGContextFillPath(ctx);
// Stroke the circle's border
CGContextAddPath(ctx, path);
CGContextStrokePath(ctx);
// Release the path
CGPathRelease(path);
// Set a dark blue color for the small inner circle
CGContextSetRGBFillColor(ctx, 0, 0, 255, 1.0f);
// Draw the center dot
CGContextBeginPath (ctx);
CGContextAddArc(ctx, rect.size.width / 2,
rect.size.height / 2,
5, 0, 2 * M_PI, NO);
CGContextFillPath(ctx);
CGContextStrokePath(ctx);
}
@end
Run Code Online (Sandbox Code Playgroud)
有了这个基础设施,我们现在可以轻松地为外圈的半径设置动画b/c CoreAnimation将处理值插值以及重绘调用.我们只需要为图层添加动画.作为一个简单的概念证明,我选择了一个简单的CAKeyframeAnimation经历3阶段动画:
// In some controller class...
- (void)addLayerAndAnimate {
CustomLayer *customLayer = [[CustomLayer alloc] init];
// Make layer big enough for the initial radius
// EDIT: You may want to shrink the layer when it reacehes it's final size
[customLayer setFrame:CGRectMake(0, 0, 205, 205)];
[self.view.layer addSublayer:customLayer];
CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"circleRadius"];
// Zoom in, oscillate a couple times, zoom in further
animation.values = [NSArray arrayWithObjects:[NSNumber numberWithFloat:100],
[NSNumber numberWithFloat:45],
[NSNumber numberWithFloat:50],
[NSNumber numberWithFloat:45],
[NSNumber numberWithFloat:50],
[NSNumber numberWithFloat:45],
[NSNumber numberWithFloat:20],
nil];
// We want the radii to be 20 in the end
customLayer.circleRadius = 20;
// Rather arbitrary values. I thought the cubic pacing w/ a 2.5 second pacing
// looked decent enough but you'd probably want to play with them to get a more
// accurate imitation of the Maps app. You could also define a keyTimes array for
// a more discrete control of the times per step.
animation.duration = 2.5;
animation.calculationMode = kCAAnimationCubicPaced;
[customLayer addAnimation:animation forKey:nil];
}
Run Code Online (Sandbox Code Playgroud)
以上是一个相当"hacky"的概念证明,因为我不确定你打算使用这种效果的具体方式.例如,如果你想在数据准备好之前振荡圆圈,那么上面的内容就不会有多大意义,因为它总会振荡两次.
一些结束说明:
MKMapView,则上面可能需要进行一些调整才能与MapKit集成.编辑:此外,出于性能原因,您可能希望确保该层只有它需要的大.也就是说,在完成较大尺寸的动画制作后,您可能需要缩小尺寸,这样您就可以根据需要使用/绘制尽可能多的空间.一个很好的方法就是找到一种方法来动画bounds(而不是circleRadius)并根据大小插值执行这个动画但是我在实现它时遇到了一些麻烦(也许有人可以在这个主题上添加一些见解).
希望这有帮助,山姆
| 归档时间: |
|
| 查看次数: |
1555 次 |
| 最近记录: |