这是关于使用MKMapKit的iPhone应用程序:
我为可拖动的注释创建了一个自定义MKAnnotationView。我想创建一个自定义动画。我设置了一个自定义图钉图像并且注释是可拖动的(这里没有显示,它发生在mapview中),代码如下:
- (void) movePinUpFinished {
[super setDragState:MKAnnotationViewDragStateDragging];
[self setDragState:MKAnnotationViewDragStateDragging];
}
- (void) setDragState:(MKAnnotationViewDragState) myState {
if (myState == MKAnnotationViewDragStateStarting) {
NSLog(@"starting");
CGPoint endPoint = CGPointMake(self.center.x,self.center.y-20);
self.center = endPoint;
[self movePinUpFinished];
}
if (myState == MKAnnotationViewDragStateEnding) {
NSLog(@"ending");
[super setDragState:MKAnnotationViewDragStateEnding];
[self setDragState:MKAnnotationViewDragStateNone];
[super setDragState:MKAnnotationViewDragStateNone];
}
if (myState == MKAnnotationViewDragStateDragging) {
NSLog(@"dragging");
}
if (myState == MKAnnotationViewDragStateCanceling) {
NSLog(@"cancel");
}
if (myState == MKAnnotationViewDragStateNone) {
NSLog(@"none");
}
}
一切正常,注释向上移动,可拖动,当我发布注释时,mapview会收到“dragstateending”。
但是现在我希望动画在一段时间内运行并将dragStateStarting更改为以下内容:
if (myState == MKAnnotationViewDragStateStarting) {
NSLog(@"starting");
CGPoint endPoint = CGPointMake(self.center.x,self.center.y-20);
[UIView animateWithDuration:1.0
animations:^{ self.center = endPoint; }
completion:^(BOOL finished){ [self movePinUpFinished]; }];
}
动画在一秒钟内按需运行,注释可拖动。但是当我发布注释时,mapview没有通过委托接收结尾。我还认识到,当我使用“UIView animateWithDuration ...”进行动画时,在开始拖动之后,当动画开始时,注释的气球就会打开。当我在没有动画的情况下设置新中心时,气球会保持关闭状态,只有在通过释放注释完成拖动后才会打开。
我做错了什么?这是覆盖setDragState的正确方法吗?我真的要打电话给超级班吗?但是如果没有在超类中设置拖尾状态,我的mapview就没有意识到拖尾状态的变化。
我想知道MKPinAnnotationView的原始实现,但因为它是一个内部类,我找不到setDragState方法的描述。
请求帮助。欢呼声,
本
答案 0 :(得分:23)
我有pin拖动工作但是试图找出为什么当你不覆盖setDragState时发生的引脚annimations - 不再适用于我的实现。你的问题包含我的回答..谢谢!
你的代码的一部分问题是,一旦你覆盖setDragState函数,根据xcode文档,你负责根据新的状态更新dragState变量。我也有点担心你的代码自己调用(setDragState调用[self setDragState])。
这是我最终得到的代码(在你的帮助下),它可以完成我所期望的所有升降机,拖动和跌落。希望这对你也有帮助!
- (void)setDragState:(MKAnnotationViewDragState)newDragState animated:(BOOL)animated
{
if (newDragState == MKAnnotationViewDragStateStarting)
{
// lift the pin and set the state to dragging
CGPoint endPoint = CGPointMake(self.center.x,self.center.y-20);
[UIView animateWithDuration:0.2
animations:^{ self.center = endPoint; }
completion:^(BOOL finished)
{ self.dragState = MKAnnotationViewDragStateDragging; }];
}
else if (newDragState == MKAnnotationViewDragStateEnding)
{
// save the new location, drop the pin, and set state to none
/* my app specific code to save the new position
objectObservations[ACTIVE].latitude = pinAnnotation.coordinate.latitude;
objectObservations[ACTIVE].longitude = pinAnnotation.coordinate.longitude;
posChanged = TRUE;
*/
CGPoint endPoint = CGPointMake(self.center.x,self.center.y+20);
[UIView animateWithDuration:0.2
animations:^{ self.center = endPoint; }
completion:^(BOOL finished)
{ self.dragState = MKAnnotationViewDragStateNone; }];
}
else if (newDragState == MKAnnotationViewDragStateCanceling)
{
// drop the pin and set the state to none
CGPoint endPoint = CGPointMake(self.center.x,self.center.y+20);
[UIView animateWithDuration:0.2
animations:^{ self.center = endPoint; }
completion:^(BOOL finished)
{ self.dragState = MKAnnotationViewDragStateNone; }];
}
}
答案 1 :(得分:3)
虽然Brian's solution有效,但它没有考虑用户手指阻止正在操纵的注释视图。
这意味着用户拖动后无法精确放置引脚。标准MKPinAnnotationView
在这方面做得很好,当手指开始拖动时,针被抬起到手指上方,并且针的视点用于放置而不是之前居住的中心点在手指下。
除此之外,我的实现还在拖动后放下引脚时添加了另一个动画,方法是抬起引脚并以更高的速度放下引脚。这与原生用户体验非常接近,并且会受到用户的欢迎。
请查看我的gist on GitHub for the code。
设置委托是可选的真的很酷,当注释视图被放回到地图上时,可选择发送通知。
答案 2 :(得分:2)
我没有多少研究Ben的代码,但它对我没用。所以我试过Brian的,它的效果非常好。非常感谢!我一直试图在拖拉期间解决注释的动画很长一段时间。
但我对Brian的解决方案有一个建议。我认为最好支持MKMapKit的委托,并通知它更改dragState并在标准委托的方法中保存新位置:- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)annotationView didChangeDragState:(MKAnnotationViewDragState)newState fromOldState:(MKAnnotationViewDragState)oldState
。这是我的代码:
DraggableAnnotationView.h:
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
@interface DraggableAnnotationView : MKAnnotationView
{
id <MKMapViewDelegate> delegate;
MKAnnotationViewDragState dragState;
}
@property (nonatomic, assign) id <MKMapViewDelegate> delegate;
@property (nonatomic, assign) MKAnnotationViewDragState dragState;
@property (nonatomic, assign) MKMapView *mapView;
@end
DraggableAnnotationView.m:
#import "DraggableAnnotationView.h"
#import "MapAnnotation.h"
@implementation DraggableAnnotationView
@synthesize delegate, dragState, mapView;
- (void)setDragState:(MKAnnotationViewDragState)newDragState animated:(BOOL)animated
{
[delegate mapView:mapView annotationView:self didChangeDragState:newDragState fromOldState:dragState];
if (newDragState == MKAnnotationViewDragStateStarting) {
// lift the pin and set the state to dragging
CGPoint endPoint = CGPointMake(self.center.x,self.center.y-20);
[UIView animateWithDuration:0.2
animations:^{ self.center = endPoint; }
completion:^(BOOL finished)
{ dragState = MKAnnotationViewDragStateDragging; }];
} else if (newDragState == MKAnnotationViewDragStateEnding) {
// drop the pin, and set state to none
CGPoint endPoint = CGPointMake(self.center.x,self.center.y+20);
[UIView animateWithDuration:0.2
animations:^{ self.center = endPoint; }
completion:^(BOOL finished)
{ dragState = MKAnnotationViewDragStateNone; }];
} else if (newDragState == MKAnnotationViewDragStateCanceling) {
// drop the pin and set the state to none
CGPoint endPoint = CGPointMake(self.center.x,self.center.y+20);
[UIView animateWithDuration:0.2
animations:^{ self.center = endPoint; }
completion:^(BOOL finished)
{ dragState = MKAnnotationViewDragStateNone; }];
}
}
- (void)dealloc
{
[super dealloc];
}
@end