スポンサーリンク

【Swift】mapviewでピン操作(現在地、長押し、drag移動など)を行う方法。〜MapAPP作成④〜

Swift
スポンサーリンク

今回の記事は地図アプリにピンを立てる方法についての記事です。
地図アプリではよくあるメソッドですね。

前回までの記事で自分の現在地を取得してmapkitview(地図上)に表示させることはできていると思います。今回は下記の続きから行えばすぐに実装できますのでまずは下記記事の自身の現在地を表示させるところまで実装して見て下さい。

ではメイン記事に進みます。

スポンサーリンク

地図アプリにピンを立てるXcode側の設定

Xcode側の設定に関しては前回記事から何も変化がありません。
前回記事どおりでここはOkです。

地図アプリで現在地にピンを立てるソースコード

コード側でピンを立てるメソッドを関数にしてmapkitviewに表示させます。

まずは現在地にピンを立てます。

import UIKit
import MapKit
import CoreLocation

class MapViewController: UIViewController,CLLocationManagerDelegate,MKMapViewDelegate {
    @IBOutlet weak var map: MKMapView!
    
    var locationManager: CLLocationManager!
    
    override func viewDidLoad() {
        super.viewDidLoad()

        locationManager = CLLocationManager()
        locationManager.delegate = self
        locationManager!.requestWhenInUseAuthorization()

        let coordinate = map.userLocation.coordinate
                // ピンを生成
        let pin = MKPointAnnotation()
                // ピンのタイトル・サブタイトルをセット
        pin.title = "テストタイトル"
        pin.subtitle = "テストサブタイトル"
                // ピンに一番上で作った位置情報をセット
        pin.coordinate = coordinate
                // mapにピンを表示する
        map.addAnnotation(pin)
        
        map.delegate = self
        //地図にピンを立てる。
    }
    // 許可を求めるためのdelegateメソッド
    func locationManager(_ manager: CLLocationManager,didChangeAuthorization status: CLAuthorizationStatus) {
            switch status {
            // 許可されてない場合
            case .notDetermined:
            // 許可を求める
                manager.requestWhenInUseAuthorization()
            // 拒否されてる場合
            case .restricted, .denied:
                // 何もしない
                break
            // 許可されている場合
            case .authorizedAlways, .authorizedWhenInUse:
                // 現在地の取得を開始
                manager.startUpdatingLocation()
                break
            default:
                break
            }
        }
}

前回と比べてピンを作成するところからが変化しています。
ピンの座標を指定してもいいのですが、今回は現在地をピンの場所に指定して見ます。

現在地をクリックすると、下記の様な表示になっています。

ヤバイ烏丸までバレてる笑。

ただ、googlemapみたく本当にピンみたいな形状をしたピンを表示させたい、長押しでピンを表示させたいなどの欲望が必ず出てきますので、下記のコードで実装できます。

地図アプリで指定の座標にピンを立てるソースコード

先ほどまでは現在地にピンを指定していたのでピンのタイトルとサブタイトルは初期状態のものでしたが、指定の場所に変更させることで赤色のピンを指定の座標に立てることができます。

import UIKit
import MapKit
import CoreLocation

class MapViewController: UIViewController,CLLocationManagerDelegate,MKMapViewDelegate {
    @IBOutlet weak var map: MKMapView!
    
    var locationManager: CLLocationManager!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        

        locationManager = CLLocationManager()
        locationManager.delegate = self
        locationManager!.requestWhenInUseAuthorization()
        
        // ロケーションマネージャーのセットアップ

                // 現在地に照準を合わす


                // 指定値にピンを立てる
                // ピンを立てたい緯度・経度をセット
        let coordinate = CLLocationCoordinate2DMake(40.0, 135.0)
                // 今回は現在地ではないのでコメントアウト
        //let coordinate = map.userLocation.coordinate
                // ピンを生成
        let pin = MKPointAnnotation()
                // ピンのタイトル・サブタイトルをセット
        pin.title = "テストタイトル"
        pin.subtitle = "テストサブタイトル"
                // ピンに一番上で作った位置情報をセット
        pin.coordinate = coordinate
                // mapにピンを表示する
        map.addAnnotation(pin)
        
        map.delegate = self
        //地図にピンを立てる。
    }
    // 許可を求めるためのdelegateメソッド
    func locationManager(_ manager: CLLocationManager,didChangeAuthorization status: CLAuthorizationStatus) {
            switch status {
            // 許可されてない場合
            case .notDetermined:
            // 許可を求める
                manager.requestWhenInUseAuthorization()
            // 拒否されてる場合
            case .restricted, .denied:
                // 何もしない
                break
            // 許可されている場合
            case .authorizedAlways, .authorizedWhenInUse:
                // 現在地の取得を開始
                manager.startUpdatingLocation()
                break
            default:
                break
            }
        }
}

ピンの場所は適当です。笑。

地図アプリでピンをクリックした際のタイトルなどの取得方法

import UIKit
import MapKit
import CoreLocation

class MapViewController: UIViewController,CLLocationManagerDelegate,MKMapViewDelegate {
    @IBOutlet weak var map: MKMapView!
    
    var locationManager: CLLocationManager!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        

        locationManager = CLLocationManager()
        locationManager.delegate = self
        locationManager!.requestWhenInUseAuthorization()
        
        // ロケーションマネージャーのセットアップ

                // 現在地に照準を合わす


                // 指定値にピンを立てる
                // ピンを立てたい緯度・経度をセット
        let coordinate = CLLocationCoordinate2DMake(40.0, 135.0)
                // 今回は現在地ではないのでコメントアウト
        //let coordinate = map.userLocation.coordinate
                // ピンを生成
        let pin = MKPointAnnotation()
                // ピンのタイトル・サブタイトルをセット
        pin.title = "テストタイトル"
        pin.subtitle = "テストサブタイトル"
                // ピンに一番上で作った位置情報をセット
        pin.coordinate = coordinate
                // mapにピンを表示する
        map.addAnnotation(pin)
        
        map.delegate = self
        //地図にピンを立てる。
    }
    // 許可を求めるためのdelegateメソッド
    func locationManager(_ manager: CLLocationManager,didChangeAuthorization status: CLAuthorizationStatus) {
            switch status {
            // 許可されてない場合
            case .notDetermined:
            // 許可を求める
                manager.requestWhenInUseAuthorization()
            // 拒否されてる場合
            case .restricted, .denied:
                // 何もしない
                break
            // 許可されている場合
            case .authorizedAlways, .authorizedWhenInUse:
                // 現在地の取得を開始
                manager.startUpdatingLocation()
                break
            default:
                break
            }
        }
  func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView) {
        if let annotation = view.annotation{
            print(annotation.title!!)
            print(annotation.coordinate)
            print(annotation.title)
            print(annotation.subtitle)
        } else {
            print("no")
        }
        // タップされたピンの位置情報
        
        
    }
 }

最下部に追加した関数「mapView」がdidselectされたviewの箇所の情報をコンソール出力してくれる関数です。

地図アプリで長押しすることでピンを立てるソースコード

こちらも地図アプリでよくある実装ですね。

長押しでピンの場所を変更します。

その際に座標等も変更になるのでなかなか複雑です。

まずは仕組みの紹介です。
長押しをしている箇所のUI情報は重要ですがそのクリックしている箇所の座標情報(緯度とか経度)がピンを地図上に挿すために最も必要です。

UI画面をクリックしている箇所の情報を取得するためには下記の追加のXcodeの設定が必要です。

まずは下記の「Long Pless gesture Recognizer」をmapviewkitの上に引っ張っていきます。storyboard上には表示がなく焦るのですが左の項目にはきちんと追加されております。落ち等の項目を下記の様にソースコードに引っ張っていきアクションを設定します。

アクションを設定する際ですが通常の設定ではなく名前をつけてtypeも変更する必要があります。Typeは下記の「UILongPressGestureRecognizer」を選んでください。

これで

OKです。

下記のコードがロングタッチの際にピンを立てるソースコードです。解説は下部で。

import UIKit
import MapKit
import CoreLocation

class MapViewController: UIViewController,CLLocationManagerDelegate,MKMapViewDelegate {
    @IBOutlet weak var map: MKMapView!
    
    var locationManager: CLLocationManager!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        locationManager = CLLocationManager()
        locationManager.delegate = self
        locationManager!.requestWhenInUseAuthorization()
        
        // ロケーションマネージャーのセットアップ
                // 指定値にピンを立てる
                // ピンを立てたい緯度・経度をセット
        let coordinate = CLLocationCoordinate2DMake(35.45, 139.56)
                // 今回は現在地とする
        //let coordinate = map.userLocation.coordinate
                // ピンを生成
        let pin = MKPointAnnotation()
                // ピンのタイトル・サブタイトルをセット
        pin.title = "テストタイトル"
        pin.subtitle = "テストサブタイトル"
                // ピンに一番上で作った位置情報をセット
        pin.coordinate = coordinate
                // mapにピンを表示する
        map.addAnnotation(pin)
        
        map.delegate = self
        //地図にピンを立てる。
    }
    // 許可を求めるためのdelegateメソッド
    func locationManager(_ manager: CLLocationManager,didChangeAuthorization status: CLAuthorizationStatus) {
            switch status {
            // 許可されてない場合
            case .notDetermined:
            // 許可を求める
                manager.requestWhenInUseAuthorization()
            // 拒否されてる場合
            case .restricted, .denied:
                // 何もしない
                break
            // 許可されている場合
            case .authorizedAlways, .authorizedWhenInUse:
                // 現在地の取得を開始
                manager.startUpdatingLocation()
                break
            default:
                break
            }
        }
    

    @IBAction func pressMap(_ sender: UILongPressGestureRecognizer) {
        
        let location:CGPoint = sender.location(in: map)
        
        if (sender.state == UIGestureRecognizer.State.ended){
                   //タップした位置を緯度、経度の座標に変換する。
            let mapPoint:CLLocationCoordinate2D = map.convert(location,toCoordinateFrom: map)
                   
                   //ピンを作成してマップビューに登録する。
            let annotation = MKPointAnnotation()
            annotation.coordinate = CLLocationCoordinate2DMake(mapPoint.latitude, mapPoint.longitude)
            annotation.title = "ピン"
            annotation.subtitle = "\(annotation.coordinate.latitude), \(annotation.coordinate.longitude)"
            map.addAnnotation(annotation)
        }
    }
}

先ほどのコードおの変更点はStoryboardに追加したガジェットにアクション(pressmap)を追加しております。
その関数内の説明をしていきます。

まずはプレスしている座標を取得できるlocationを定義してその座標をconvertメソッドで座標に変換しています。この座標がピンをさす座標になります。

ここまでこればいままでと同じ流れです。ピンを生成して、その座標にさすのみです。

ピンを立てるだけでもなんかアプリぽいです。

地図アプリでピンを移動させる方法

ピンの最後の操作としてドラッグ移動の方法を記載いたします。

import UIKit
import MapKit
import CoreLocation

class MapViewController: UIViewController,CLLocationManagerDelegate,MKMapViewDelegate {
    @IBOutlet weak var map: MKMapView!
    
    var locationManager: CLLocationManager!
    let annotation = MKPointAnnotation()
    override func viewDidLoad() {
        super.viewDidLoad()
        tionManager = CLLocationManager()
        locationManager.delegate = self
        locationManager!.requestWhenInUseAuthorization()

                // ピンを立てたい緯度・経度をセット
        let coordinate = CLLocationCoordinate2DMake(35.45, 139.56)
                // 今回は現在地とする
        //let coordinate = map.userLocation.coordinate
                // ピンを生成
        let pin = MKPointAnnotation()
                // ピンのタイトル・サブタイトルをセット
        pin.title = "テストタイトル"
        pin.subtitle = "テストサブタイトル"
                // ピンに一番上で作った位置情報をセット
        pin.coordinate = coordinate
                // mapにピンを表示する
        map.addAnnotation(pin)
        
        map.delegate = self
        //地図にピンを立てる。
    }
    // 許可を求めるためのdelegateメソッド
    func locationManager(_ manager: CLLocationManager,didChangeAuthorization status: CLAuthorizationStatus) {
            switch status {
            // 許可されてない場合
            case .notDetermined:
            // 許可を求める
                manager.requestWhenInUseAuthorization()
            // 拒否されてる場合
            case .restricted, .denied:
                // 何もしない
                break
            // 許可されている場合
            case .authorizedAlways, .authorizedWhenInUse:
                // 現在地の取得を開始
                manager.startUpdatingLocation()
                break
            default:
                break
            }
        }
    

    @IBAction func pressMap(_ sender: UILongPressGestureRecognizer) {
        
        let location:CGPoint = sender.location(in: map)
        
        if (sender.state == UIGestureRecognizer.State.ended){
                   //タップした位置を緯度、経度の座標に変換する。
            let mapPoint:CLLocationCoordinate2D = map.convert(location,toCoordinateFrom: map)
                   
                   //ピンを作成してマップビューに登録する。
            
            annotation.coordinate = CLLocationCoordinate2DMake(mapPoint.latitude, mapPoint.longitude)
            annotation.title = "ピン"
            annotation.subtitle = "\(annotation.coordinate.latitude), \(annotation.coordinate.longitude)"
            map.addAnnotation(annotation)
        }
    }
    func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
        
        let testView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: nil)
        
        //吹き出しを表示可能にする。
        testView.canShowCallout = true
        return testView
    }
}

リアルタイムで表示を更新する関数を下部につけてピンの宣言を関数内ではなくかなり広域な箇所で宣言しております。このクラス内ではどこでも操作できるように変更しております。

かなり長い記事になってしまった。。

ただこれでピンお操作に関してはかなり網羅できたと思いますのでよい備忘録兼参考記事になれば幸いです。

本記事を読んでいただき感謝です。サイトを訪れていただいた方はプログラミング勉強中かと思いますのでプログラミング勉強のコツを合わせてご紹介。

スポンサーリンク
スポンサーリンク
スポンサーリンク

ブログに関しては500円程度かかりますが、それ以外は無料です。知識の吸収と並行してアウトプットは非常に効率が良いです。テックアカデミーに関しては講座レベルが高いにも関わらず、無料体験や人気口座も大幅値下げがあるので、重点的に学びたいものを無料体験してみてください。

転職時にも、エンジニアからテックアカデミー・Paizaは認知度が高いので、未経験入社採用を行う際履歴書で目に留まります。特にPaizaのスキルレベルA・SなどはIT業界でも評価されます。

テックアカデミー・Paizaの無料登録ができる期間中にぜひご利用してみてください。私も活用経験ありです。

Swift
スポンサーリンク
スポンサーリンク
ともぶろぐ

コメント

  1. […] 過去参考記事・map長押しでピンを表示させる方法 […]

  2. […] Xcode側の設定は以前のmapview関連の記事を参照してまずは地図を表示させ、2点間にピンを配置するところまでは準備ください。参考記事。 […]

タイトルとURLをコピーしました