iphone - 创建像用户位置蓝色大理石水滴这样的动画
Posted
技术标签:
【中文标题】iphone - 创建像用户位置蓝色大理石水滴这样的动画【英文标题】:iphone - create animation like user location Blue marble drop 【发布时间】:2011-08-22 16:21:17 【问题描述】:你知道如何在 MKMapView 中创建像 Blue Marble drop User-Location 这样的动画吗?
【问题讨论】:
您是要制作类似的动画,还是要在地图视图中显示标准位置指示器? 我喜欢制作类似的动画,谢谢。 您在帖子中找到的答案 [在此处输入链接描述][1] [1]:***.com/questions/1437568/… 【参考方案1】:虽然我不确定 Apple 是如何实现这种效果的具体细节,但我觉得这是一个使用 CoreAnimation 和自定义动画属性的绝佳机会。 This post 提供了有关该主题的一些不错的背景。我假设您所指的“Blue Marble drop”动画是以下序列:
-
淡蓝色大圆圈放大到框架中
大的浅蓝色圆圈在两个相对较大的半径之间摆动,因为位置是
计算出来的
浅蓝色大圆圈放大用户位置上的深蓝色小圆圈
虽然这可能会稍微简化流程,但我认为这是一个很好的起点,可以相对轻松地添加更复杂/详细的功能(即随着较大圆圈会聚,小黑圈会脉动。)
我们需要的第一件事是一个自定义的 CALayer 子类,它为我们的外部大浅蓝色圆圈半径提供一个自定义属性:
#import <QuartzCore/QuartzCore.h>
@interface CustomLayer : CALayer
@property (nonatomic, assign) CGFloat circleRadius;
@end
和实施:
#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
有了这个基础设施,我们现在可以轻松地为外圆的半径设置动画,因为 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];
以上是一个相当“hacky”的概念证明,因为我不确定您打算使用这种效果的具体方式。例如,如果您想在数据准备好之前让圆振荡,那么上面的方法就没有多大意义,因为它总是会振荡两次。
一些结束语:
再说一次,我不确定您对这种效果的意图。如果,对于 例如,您将其添加到MKMapView
,以上可能需要
一些调整以与 MapKit 集成。
链接的帖子表明上述方法需要 ios 3.0+ 和 OS X 10.6+ 中的 CoreAnimation 版本
谈到链接的帖子(就像我经常做的那样),非常感谢 Ole Begemann,他写了 it 并出色地解释了 CoreAnimation 中的自定义属性。
编辑:另外,出于性能原因,您可能希望确保该层仅与需要的一样大。也就是说,在您从较大尺寸完成动画后,您可能希望缩小尺寸,以便您只使用/绘制尽可能多的空间。一个很好的方法是找到一种方法动画bounds
(而不是circleRadius
)并根据大小插值执行此动画,但我在实现它时遇到了一些麻烦(也许有人可以添加一些见解关于那个主题)。
希望这会有所帮助, 山姆
【讨论】:
中间的线条和蓝色圆圈看起来像素化、锯齿状......我能做些什么来解决这个问题,让它变得平滑? 想通了.. customLayer.contentsScale = [UIScreen mainScreen].scale;【参考方案2】:将此添加到您的地图对象:
myMap.showsUserLocation = TRUE;
【讨论】:
以上是关于iphone - 创建像用户位置蓝色大理石水滴这样的动画的主要内容,如果未能解决你的问题,请参考以下文章