地図を長押しして上からピン落とす

プロジェクト作成

Single View Applicationを選択。

Mapkit.frameworkをプロジェクトに登録

プロジェクトのアプリケーションの設定画面で、Mapkit.frameworkを追加

ViewにMKMapViewを追加

StoryBoardの画面で「Map View」をViewに張り付け、「map」と言う名前でOutletの設定を行う。

ViewController.h の@interface宣言に「」を追加

@interface ViewController : UIViewController<MKMapViewDelegate>
@property (weak, nonatomic) IBOutlet MKMapView *map;

@end

初期処理いろいろ

ここからは「ViewController.m」の編集になる。

MapViewの長押しを検出するために「UILongPressGestureRecognizer」を作成してMapViewに追加。

    UILongPressGestureRecognizer *longPressGesture;
    longPressGesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self
                                                                     action:@selector(handleLongPressGesture:)];
    [_map addGestureRecognizer:longPressGesture];
    _map.delegate = self;

selectorで指定している「handleLongPressGesture」は長押しが検出されたときに
呼び出される関数。

それから、後でピンを追加するときにアニメーションにするため、
MapViewのDelegateにselfをセットしている。

長押し検出時の処理

長押ししたMapViewの画面上の座標値(例:x=150,y=165)を
地図上の座標値(例:latitude:35.674882,longitude:139.772148)に変換するため、

// MKMapView.h
- (CLLocationCoordinate2D)convertPoint:(CGPoint)point toCoordinateFromView:(UIView *)view;

を呼び出して変換している。

- (void)handleLongPressGesture:(UILongPressGestureRecognizer *)gesture
{
    if (gesture.state == UIGestureRecognizerStateBegan) {  // 長押し検出開始時のみ動作
        
        CGPoint touchedPoint = [gesture locationInView:_map];
        CLLocationCoordinate2D touchCoordinate = [_map convertPoint:touchedPoint toCoordinateFromView:_map];
        
        [self setAnnotation:touchCoordinate mapMove:NO animated:NO];
    }
}

地図にピンを配置

指定した地図上の座標値にピンを立てる。

MKPointAnnotationに座標値を指定するだけ。
このままだとピンが上から落ちてくるアニメーションにはならないため、
後で処理を追加する。

また、ピンの周りに円を表示するため、MKCircleを作成している。
こちらもこのままでは表示されない。

-(void)setAnnotation:(CLLocationCoordinate2D) point mapMove:(BOOL)mapMove
            animated:(BOOL)animated{
    // ピンを全て削除
    [_map removeAnnotations: _map.annotations];

    // 新しいピンを作成
    MKPointAnnotation *anno = [[MKPointAnnotation alloc] init];
    anno.coordinate = point;
    // ピンを追加
    [_map addAnnotation:anno];
    
    // ピンの周りに円を表示
    MKCircle* circle = [MKCircle circleWithCenterCoordinate:point radius:500];  // 半径500m
    [_map removeOverlays:_map.overlays];
    [_map addOverlay:circle];
}

ピンが落ちてくるアニメーション処理を追加

「animatesDrop = YES」で上から落ちてくるアニメーションになる。

MapViewのDelegateにselfを設定しておかないとこの関数は呼ばれない。

- (MKAnnotationView *)mapView:(MKMapView *)mapView
            viewForAnnotation:(id )annotation
{
    static NSString* Identifier = @"PinAnnotationIdentifier";
    MKPinAnnotationView* pinView;
    pinView = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:Identifier];
    
    if (pinView == nil) {
        pinView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation
                                                  reuseIdentifier:Identifier];
        pinView.animatesDrop = YES;
        return pinView;
    }
    pinView.annotation = annotation;
    return pinView;
}

ピンの周りの円を描画

ピンの周りに赤い円を描画する処理。
MapViewのDelegateにselfを設定しておかないとこの関数は呼ばれない。

- (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id <MKOverlay>)overlay
{
    MKCircle* circle = overlay;
    MKCircleView* circleOverlayView =   [[MKCircleView alloc] initWithCircle:circle];
    
    circleOverlayView.strokeColor = [UIColor colorWithRed:1.0 green:0.0 blue:0.0 alpha:0.5];
    circleOverlayView.lineWidth = 4.;
    circleOverlayView.fillColor = [UIColor colorWithRed:1.0 green:0.0 blue:0.0 alpha:0.25];
    return circleOverlayView;
}

実行結果

こんな感じ。

地図を長押しすると、押したところにピンが落ちてくる。

ソースはこちら。

https://github.com/yuriken27/work/tree/master/MapTest