我怎样才能使用MKAnnotationView创build一个自定义的“pin-drop”animation?
我有一个MKMapView
的实例,并希望使用自定义注释图标,而不是由MKPinAnnotationView提供的标准图钉图标。 所以,我设置了一个名为CustomMapAnnotation的MKAnnotationView的子类,并覆盖-(void)drawRect:
绘制一个CGImage。 这工作。
当我尝试复制由.animatesDrop
提供的.animatesDrop
function时遇到麻烦; 我喜欢我的图标逐渐出现,从上面,从左到右的顺序,当注释被添加到MKMapView
实例。
这里是 – (void)drawRect:用于CustomMapAnnotation,它在你绘制UIImage(这是第二行所做的)时工作:
- (void)drawRect:(CGRect)rect { [super drawRect:rect]; [((Incident *)self.annotation).smallIcon drawInRect:rect]; if (newAnnotation) { [self animateDrop]; newAnnotation = NO; } }
添加animateDrop
方法时会遇到麻烦:
-(void)animateDrop { CGContextRef myContext = UIGraphicsGetCurrentContext(); CGPoint finalPos = self.center; CGPoint startPos = CGPointMake(self.center.x, self.center.y-480.0); self.layer.position = startPos; CABasicAnimation *theAnimation; theAnimation=[CABasicAnimation animationWithKeyPath:@"position"]; theAnimation.fromValue=[NSValue valueWithCGPoint:startPos]; theAnimation.toValue=[NSValue valueWithCGPoint:finalPos]; theAnimation.removedOnCompletion = NO; theAnimation.fillMode = kCAFillModeForwards; theAnimation.delegate = self; theAnimation.beginTime = 5.0 * (self.center.x/320.0); theAnimation.duration = 1.0; [self.layer addAnimation:theAnimation forKey:@""]; }
这是行不通的,可能有很多原因。 我现在不会涉及所有的人。 我想知道的主要是如果方法完全合理,或者我应该尝试一些完全不同的东西。
我也尝试将整个事件打包成一个animation事务,以便beginTime参数实际上可以工作。 这似乎什么也没有做。 我不知道这是因为我错过了一些关键点,还是因为MapKit以某种方式摧毁了我的animation。
// Does nothing [CATransaction begin]; [map addAnnotations:list]; [CATransaction commit];
如果任何人有任何这样的animationMKMapAnnotations的经验,我会喜欢一些提示,否则,如果你可以提供CAAnimationbuild议的方法,这也会很好。
Paul Shapiro的代码存在一个问题,那就是当你在用户目前正在查看的地方添加注释时,它不会处理。 这些注释会在放下之前浮在空中,因为它们被移动到用户的可见地图矩形中。
另一个就是它也下降了用户位置的蓝点。 使用下面的代码,您可以在屏幕外同时处理用户位置和大量地图注释。 我也添加了一个不错的反弹;)
- (void)mapView:(MKMapView *)mapView didAddAnnotationViews:(NSArray *)views { MKAnnotationView *aV; for (aV in views) { // Don't pin drop if annotation is user location if ([aV.annotation isKindOfClass:[MKUserLocation class]]) { continue; } // Check if current annotation is inside visible map rect, else go to next one MKMapPoint point = MKMapPointForCoordinate(aV.annotation.coordinate); if (!MKMapRectContainsPoint(self.mapView.visibleMapRect, point)) { continue; } CGRect endFrame = aV.frame; // Move annotation out of view aV.frame = CGRectMake(aV.frame.origin.x, aV.frame.origin.y - self.view.frame.size.height, aV.frame.size.width, aV.frame.size.height); // Animate drop [UIView animateWithDuration:0.5 delay:0.04*[views indexOfObject:aV] options:UIViewAnimationCurveLinear animations:^{ aV.frame = endFrame; // Animate squash }completion:^(BOOL finished){ if (finished) { [UIView animateWithDuration:0.05 animations:^{ aV.transform = CGAffineTransformMakeScale(1.0, 0.8); }completion:^(BOOL finished){ [UIView animateWithDuration:0.1 animations:^{ aV.transform = CGAffineTransformIdentity; }]; }]; } }]; } }
首先,你需要让你的视图控制器实现MKMapViewDelegate,如果它尚未。
然后,执行这个方法:
- (void)mapView:(MKMapView *)mapView didAddAnnotationViews:(NSArray *)views { MKAnnotationView *aV; for (aV in views) { CGRect endFrame = aV.frame; aV.frame = CGRectMake(aV.frame.origin.x, aV.frame.origin.y - 230.0, aV.frame.size.width, aV.frame.size.height); [UIView beginAnimations:nil context:NULL]; [UIView setAnimationDuration:0.45]; [UIView setAnimationCurve:UIViewAnimationCurveEaseInOut]; [aV setFrame:endFrame]; [UIView commitAnimations]; } }
将您的注释添加到MapView中,并在添加它们时,将调用此委托方法,并在添加时从顶部到底部对这些引脚进行animation处理。
时间和定位的值可以改变一点点,但我已经调整了,使其看起来最接近传统的下降(据我testing)。 希望这可以帮助!
或者,如果您正在制作MKAnnotationView子类,则可以使用didMoveToSuperview
触发animation。 下面的结果是稍有“压扁”效果
#define kDropCompressAmount 0.1 @implementation MyAnnotationViewSubclass ... - (void)didMoveToSuperview { CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform"]; animation.duration = 0.4; animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn]; animation.fromValue = [NSValue valueWithCATransform3D:CATransform3DMakeTranslation(0, -400, 0)]; animation.toValue = [NSValue valueWithCATransform3D:CATransform3DIdentity]; CABasicAnimation *animation2 = [CABasicAnimation animationWithKeyPath:@"transform"]; animation2.duration = 0.10; animation2.beginTime = animation.duration; animation2.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut]; animation2.toValue = [NSValue valueWithCATransform3D:CATransform3DScale(CATransform3DMakeTranslation(0, self.layer.frame.size.height*kDropCompressAmount, 0), 1.0, 1.0-kDropCompressAmount, 1.0)]; animation2.fillMode = kCAFillModeForwards; CABasicAnimation *animation3 = [CABasicAnimation animationWithKeyPath:@"transform"]; animation3.duration = 0.15; animation3.beginTime = animation.duration+animation2.duration; animation3.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut]; animation3.toValue = [NSValue valueWithCATransform3D:CATransform3DIdentity]; animation3.fillMode = kCAFillModeForwards; CAAnimationGroup *group = [CAAnimationGroup animation]; group.animations = [NSArray arrayWithObjects:animation, animation2, animation3, nil]; group.duration = animation.duration+animation2.duration+animation3.duration; group.fillMode = kCAFillModeForwards; [self.layer addAnimation:group forKey:nil]; }
对于Michael Tyson的回应(我到目前为止还无法评论),我build议在didMoveToSuperview中插入以下代码以正确重用MKAnnotationView,以便再次执行animation,然后模仿注释的顺序添加
用分频器和乘法器来播放不同的视觉效果…
- (void)didMoveToSuperview { //necessary so it doesn't add another animation when moved to superview = nil //and to remove the previous animations if they were not finished! if (!self.superview) { [self.layer removeAllAnimations]; return; } float xOriginDivider = 20.; float pos = 0; UIView *mySuperview = self.superview; while (mySuperview && ![mySuperview isKindOfClass:[MKMapView class]]) mySuperview = mySuperview.superview; if ([mySuperview isKindOfClass:[MKMapView class]]) //given the position in the array // pos = [((MKMapView *) mySuperview).annotations indexOfObject:self.annotation]; // left to right sequence; pos = [((MKMapView *) mySuperview) convertCoordinate:self.annotation.coordinate toPointToView:mySuperview].x / xOriginDivider; float yOffsetMultiplier = 20.; float timeOffsetMultiplier = 0.05; CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform"]; animation.duration = 0.4 + timeOffsetMultiplier * pos; animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn]; animation.fromValue = [NSValue valueWithCATransform3D:CATransform3DMakeTranslation(0, -400 - yOffsetMultiplier * pos, 0)]; animation.toValue = [NSValue valueWithCATransform3D:CATransform3DIdentity]; // rest of animation group... }
我认为更好的select是将“animatesDrop”设置为YES。 这是MKPinAnnotationView的一个属性。