【Swift】MapKitを使ってみた 

以前MapKitを使ってアプリを作成してことがあったので、備忘録含めまとめようと思います。

# MKMapとは？
アプリ状に簡単に地図を表示することのできるフレームワークです。

# 実際に使ってみた
## Map上に現在地を表示する
#### 1. StoryboardにMKMapViewを追加
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2880542/7d6242aa-346f-f272-b0da-6a4b35e961aa.png" width="250px">

#### 2. info.plistに許可設定の内容を記述
info.plistに下記内容を追加する。
`Privacy - Location When In Use Usage Description`
![スクリーンショット 2022-12-16 2.15.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2880542/8ee4a457-ca06-5d0b-5477-87857041f51f.png)
※上記画像内「位置情報を取得します。」は好きな文章で良いです。

設定すると、許可を求めるダイアログで下記のように表示されます。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2880542/eb888037-fa42-1aa5-9a68-df13cad95a79.png" width="250px">

#### 3. MapKitのインポート
```swift:ViewController.swift
import MapKit
```

#### 4. 位置情報の使用許可を求めるメソッドの実装
```swift:ViewContoroller.swift
var locationManager: CLLocationManager! // locationManagerの宣言

override func viewDidLoad() {
 super.viewDidLoad()

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

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
    }
}
```
アプリで位置情報を取得するための使用許可を求めるメソッドです。
許可されている場合にのみ現在地の取得を行います。
CLLocationManagerクラスを用いて位置情報関連を取得していきます。
`manager.requestWhenInUseAuthorization()`で2で設定したダイアログが表示され、許可を求めます。

#### 5. 実行
これでエラーもなく正しく記述さえできていれば現在地がマップ上で表示されると思います。
注意点として、実機でしか現在地を表示することができません。
しかし、シミュレータ内で緯度と軽度を設定し、それを現在地とすることで表示されるかどうか試すことができます。
シミュレータを選択した状態で、`Features > Location > Cunstom Location`内で設定が可能です。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2880542/f266b02f-45cd-90a1-79cd-f113096af523.png" width="500px">

無事にビルドできれば、下記画像のように現在地に青いピンが表示されると思います。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2880542/ae5d1d2d-e795-f030-86ef-3733f961b9ce.png" width="250px">

しかし、こんなに拡大された状態で表示されないと思います。
そこで、地図の縮尺を設定することができます。
```swift:ViewController.swift(ViewDidLoad内に設定)
var region:MKCoordinateRegion = self.mapView.region
region.center = self.mapView.userLocation.coordinate　// Mapの焦点を現在地に設定
region.span.latitudeDelta = 0.02 // 倍率の設定
region.span.longitudeDelta = 0.02 // 倍率の設定
self.mapView.setRegion(region,animated:false) // 倍率の適用
```

これで倍率も変更し、見やすい感じになったと思います。

## Map上にピンを設定する
次に、指定した箇所に赤いピンを立てていきたいと思います。
今回は、仮に大阪駅にピンを立ててみたいと思います。

```swift:ViewController.swift
override func viewDidLoad() {
    self.addPin(latitude: 34.7024, longitude: 135.4959) // 追記
}

func addPin(latitude: Double, longitude: Double) {
    let pin = MKPointAnnotation() // ピンを生成
    // ピンのタイトル・サブタイトルをセット
    pin.title = "大阪駅" // タイトル
    pin.subtitle = "大阪駅にピン留めしています。" // サブタイトル
    pin.coordinate = CLLocationCoordinate2D(latitude: latitude, longitude: longitude) // 位置情報の設定
    self.mapView.addAnnotation(pin) // mapにピンを表示する
}
```

Map上のピンは、MKPointAnnotationというアノテーションを追加することで、
ピンを立てることができます。
タイトルは赤いピンの下に表示される文字になります。
サブタイトルは、ピンをタップした後に吹き出しを表示することができるのですが、その際に表示されます。（吹き出しは下記で設定します。）

上記設定が完了すると、下記画像のようにピンが表示されます。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2880542/6488f546-e009-0319-0cae-525b086215d9.png" width="250px">

## ピンに吹き出しを設定する
デリゲートメソッドを用いることで、吹き出しを設定することができます。
```swift:ViewController.swift
extension ViewController: CLLocationManagerDelegate, MKMapViewDelegate {
    //アノテーションビューを返すメソッド
     func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
         // MapViewのdelegateメソッド、viewFor annotationを定義している場合、
         // 地図上に青点のannotationを表示する処理がオーバライドされてしまう。
         // 青点のannotation(現在地表示しているピン)のみ、処理しないという記述を行うことで正しい動きになる。
         if annotation.title == "My Location"{
             return nil
         }

         //アノテーションビューの作成
         let pinView = MKMarkerAnnotationView(annotation: annotation, reuseIdentifier: nil)
    
         //吹き出しを表示可能にする
         pinView.canShowCallout = true
    
         // 例で削除ボタンの作成
         let button = UIButton()
         button.frame = CGRect(x:0,y:0,width:40,height:40)
         button.setImage(UIImage(systemName: "trash"), for: .normal)
         button.tintColor = UIColor.red

         //右側に削除ボタンを追加
         pinView.rightCalloutAccessoryView = button
             
         return pinView
     }
}
```

上記内容を設定することで、下記画像のように、ピンをタップした際に吹き出しが表示されます。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2880542/979861d3-1dde-3893-82d4-2c04641e9ebd.png" width="250px">

## 立てたピンを削除する
```swift:ViewController.swift
extension ViewController: CLLocationManagerDelegate, MKMapViewDelegate { // 追加
    //吹き出しアクササリー押下時の呼び出しメソッド
    func mapView(_ mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) {
        guard let annotation = view.annotation else {
            return
        }
        //右のボタンが押された場合はピンを消す。
        self.mapView.removeAnnotation(annotation)
    }
}
```

ピンを随時削除することができます。
今回は、吹き出し内の削除ボタンをタップすることで削除できるようにしてあります。

# まとめ
そのほかにもピンの色を変更したり、色々できそうです。
今後は、場所を検索して、該当するところにピンを立てたりもしてみたいと思います。