マップから注釈を追加および削除せずに MKAnnotation の座標を移動することは可能ですか?
11 に答える
かなり簡単な方法を見つけました。プレーヤーの注釈を削除してから再度追加することなく、プレーヤーの位置をスムーズに更新したかったのです。これは、iOS4 より前のアプリでうまく機能し、ピンを移動し、ピンの新しい場所を地図の中心に配置します。
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.5];
[UIView setAnimationCurve:UIViewAnimationCurveLinear];
[player setCoordinate:aLoc.coordinate];
[mapView setCenterCoordinate:aLoc.coordinate animated:NO];
[UIView commitAnimations];
これは同じことですが、iOS4 で推奨されるブロック機能を使用しています。
[UIView animateWithDuration:0.5 animations:^{
[player setCoordinate:aLoc.coordinate];
[mapView setCenterCoordinate:aLoc.coordinate animated:NO];
}];
コース外で注釈を削除および追加することなく、実際に可能です。
MKAnnotation の座標を観察し、変更されたときに MKAnnotationView の位置を更新する必要があります。または、独自の MKAnnotation と MKAnnotationView を派生させて、それらを「移動可能」にすることもできます (これはおそらくより洗練された方法です)。
注釈の位置もアニメーション化する詳細な例については、 Moving-MKAnnotationViewを参照してください。
KVOを使用するだけです:
[annotation willChangeValueForKey:@"coordinate"];
[annotation didChangeValueForKey:@"coordinate"];
MKAnnotation に setCoordinate メソッドがある場合は、次の行をそのまま含めます。
- (void)setCoordinate:(CLLocationCoordinate2D)newCoordinate {
[self willChangeValueForKey:@"coordinate"];
coordinate = newCoordinate;
[self didChangeValueForKey:@"coordinate"];
}
MKPointAnnotation をサブクラス化すると、マップ上の注釈ビューを新しい座標に自動的に更新する機能があります。
それがより一般的に可能かどうかはわかりませんが、独自のカスタムMKAnnotationViewがある場合はそうです。
http://spitzkoff.com/craig/?p=108でCraigSpitzkoffによって文書化されたアプローチを適応させることができました。
- カスタムMKAnnotationViewにMKAnnotationオブジェクトへの参照を与える
- updateCoordinatesメソッドをMKAnnotationオブジェクトに追加し、アノテーションの場所を変更するときに呼び出します
- カスタムMKAnnotationViewでregionChangedを呼び出して、それ自体を再配置するタイミングを通知します(たとえば、MKAnnotationが座標を更新した場合)。
- カスタムMKAnnotationViewが所有する内部ビューオブジェクトのdrawRectで、MKAnnotationの座標を使用して再配置できます(MKAnnotationへの参照を保持しています)。
このアプローチをさらに単純化できる可能性があります。すべての状況で内部ビューオブジェクトを必要としない場合があります。
ほとんどの回答は、注釈がMKPlacemark拡張を介して作成されているという事実に基づいています。しかし、MKAnnotationプロトコルのみを実装する他のオブジェクト(つまり、マーカーのカスタム画像)はどうでしょうか?setCoordinateメソッドはありません。だからここに100グラムによって提供されるコードに基づく答えがあります
MKAnnotationView *av = [self.mapView viewForAnnotation:user];
//user is an object which implements <MKAnnotation>
// You will probably get your MKAnnotationView in your own way
if (av){
// here user returns CLLocationCoordinate2D coordinate
MKMapPoint mapPoint = MKMapPointForCoordinate([user getLastLocation]);
// converting mapPoint to CGPoint
CGPoint newPos;
CGFloat zoomFactor = self.mapView.visibleMapRect.size.width / self.mapView.bounds.size.width;
newPos.x = mapPoint.x/zoomFactor;
newPos.y = mapPoint.y/zoomFactor;
// animation for annotation's move
static NSString *POSITION_KEY=@"positionAnimation";
static NSString *PATH_ANIMATION_KEY=@"position";
if (MKMapRectContainsPoint(self.mapView.visibleMapRect, mapPoint)) {
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:PATH_ANIMATION_KEY];
animation.fromValue = [NSValue valueWithCGPoint:av.center];
animation.toValue = [NSValue valueWithCGPoint:newPos];
animation.duration = 0.3;
animation.delegate = av;
animation.fillMode = kCAFillModeForwards;
[av.layer addAnimation:animation forKey:POSITION_KEY];
}
// moving view
av.center = newPos;
したがって、基本的に、対応するMKAnnotationViewを取得する必要があります。これは、すべての注釈とその新しい場所を介した反復によっても実現できます。すべての配列ホルダー(NSMutableArray * mapAnnotaions)を作成したので、次のように繰り返すことができます。
for (id annotation in mapAnnotaions) {call refresh method here for id}
注釈の座標またはその他のプロパティを更新した後、次の MKMapViewDelegate メソッドを呼び出して、注釈を再描画します。
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation;
例えば:
myAnnotation.coordinate = CLLocationCoordinate2DMake([newLat doubleValue], [newLon doubleValue]);
[self mapView:self.mapView viewForAnnotation:myAnnotation];
注釈への参照を保持し、座標プロパティを変更してから、注釈をマップに再度追加すると、注釈ビューの位置が更新されます。注釈を削除する必要はありません (注釈ビューが一時的に消えます)。ただし、これは、注釈座標が更新されたときの適切な遷移にはなりません。また、メモリ リークも発生せず、マップに複数の同じ注釈が追加されることもありません (マップビューで注釈の数を見ると、注釈を再追加しても一定のままです)。
私のMapKitDragAndDropサンプルを見てください。iPhone OS 3 と iOS 4 の両方で MKAnnotation を更新して MKAnnotationView を移動できます (組み込みのドラッグ サポートを使用します)。
MKAnnotation オブジェクトの座標を変更して、MKMapView に変更を通知することはできないようです。
ただし、以前の注釈をマップから削除し、注釈オブジェクトの座標を変更して、マップに再度追加することはうまく機能します。
[theMapView removeAnnotation:myAnnotation];
[myAnnotation setLatitude:newLatitude];
[theMapView addAnnotation:myAnnotation];
なんでこんな風にしたくないの?