MkMapViewの使い方(swift版)


MkMapViewを使って地図系アプリを作っているのですが、意外にまとまった情報がありませんでした。そこで簡単な地図アプリ作成手順として情報を整理しました。

作成したアプリは、[Github](https://github.com/unokun/SimpleMap)に置いています。

# 機能
以下の機能を実装しました。
* 現在位置を地図上に表示できる
* 緯度経度をラベル表示できる
* 現在位置のトラッキングを開始・終了できる
* 地図のスケールを自動的に調整できる
* 現在位置にピンをつけることができる
* ピンのコールアウトをタップしないで表示する


# アプリ作成手順
1. プロジェクト作成
2. アプリで位置情報を使うための設定
3. 位置情報取得処理追加
4. ピン表示処理追加

# プロジェクト作成
[ここ](http://blog.koogawa.com/entry/2015/11/01/024007)を参考にして、プロジェクトを作成します。

* Single View Applicationを選択してプロジェクトを作成します。
* 地図ライブラリ(MapKit.framework)を追加します。
* Storyboardを使ってMap Kit Viewを追加します。

位置情報表示のためのラベルと位置情報取得開始・終了用ボタンを追加しています。

# アプリで位置情報を使うための設定
位置情報を使うための以下のキーをinfo.plistに追加します。
* Privacy - Location When In Use Usage Description
* Privacy - Location Always Usage Description

アプリ初回起動時にユーザーに許可を出す時のメッセージになります。

```swift
		// 位置情報取得時に、リクエストを出すと
        locationManager!.requestWhenInUseAuthorization()

	// このメソッドが呼ばれます
    func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
        switch status {
        case .notDetermined:
            manager.requestWhenInUseAuthorization()
        case .restricted, .denied:
            break
        case .authorizedAlways, .authorizedWhenInUse:
            break
        }
    }
```

![写真 2016-12-31 7 57 04.png](https://qiita-image-store.s3.amazonaws.com/0/5247/06c0680f-0aee-9e4e-13cf-e215586db631.png "写真 2016-12-31 7 57 04.png")


# 位置情報取得処理追加
　CLLocationManagerクラスを使って位置情報の取得します。
　　
## 開始
startUpdatingLocationを実行します。
位置情報が更新された場合には、CLLocationManagerDelegateプロトコルのlocationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation])が呼ばれます。

```swift
    @IBAction func tapStartButton(_ sender: UIButton) {
        if locationManager != nil { return }
        locationManager = CLLocationManager()
        locationManager!.delegate = self
        locationManager!.requestWhenInUseAuthorization()
        
        if CLLocationManager.locationServicesEnabled() {
            locationManager!.startUpdatingLocation()
        }
        // tracking user location
        mapView.userTrackingMode = MKUserTrackingMode.followWithHeading
        mapView.showsUserLocation = true

    }
    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        guard let newLocation = locations.last else {
            return
        }
        
        let location:CLLocationCoordinate2D
            = CLLocationCoordinate2DMake(newLocation.coordinate.latitude, newLocation.coordinate.longitude)
        let latitude = "".appendingFormat("%.4f", location.latitude)
        let longitude = "".appendingFormat("%.4f", location.longitude)
        latLabel.text = "latitude: " + latitude
        lngLabel.text = "longitude: " + longitude
        
        // update annotation
        mapView.removeAnnotations(mapView.annotations)

        let annotation = MKPointAnnotation()
        annotation.coordinate = newLocation.coordinate
        mapView.addAnnotation(annotation)
        mapView.selectAnnotation(annotation, animated: true)
        
        // Showing annotation zooms the map automatically.
        mapView.showAnnotations(mapView.annotations, animated: true)
        
    }    
```

## 終了
stopUpdatingLocationを実行します。

```swift
        guard let manager = locationManager else { return }
        manager.stopUpdatingLocation()
        manager.delegate = nil
        locationManager = nil
        latLabel.text = "latitude: "
        lngLabel.text = "longitude: "
        
        // untracking user location
        mapView.userTrackingMode = MKUserTrackingMode.none
        mapView.showsUserLocation = false
        mapView.removeAnnotations(mapView.annotations)
```

# ピン表示
ピン表示にはMKPointAnnotationクラスを使います。
現在位置を一つだけ表示するために、全削除して追加しています。

```swift
        mapView.removeAnnotations(mapView.annotations)

        let annotation = MKPointAnnotation()
        annotation.coordinate = newLocation.coordinate
        mapView.addAnnotation(annotation)
        mapView.selectAnnotation(annotation, animated: true)
        
        mapView.showAnnotations(mapView.annotations, animated: true)
```

## 開始ボタンタップする前
初期表示は日本がすべて表示されます。
![写真 2016-12-31 7 59 08.png](https://qiita-image-store.s3.amazonaws.com/0/5247/0b506eae-c56b-da00-109a-e588f2718ed4.png "写真 2016-12-31 7 59 08.png")

全部のピンを表示してくれます。
開始ボタンをタップ時にmapView.showAnnotationsを実行するとすべてのピンが表示されます。
mapView.setRegionを使ってズーム率を指定することができます。

```swift
        var region:MKCoordinateRegion = mapView.region
        region.center = location
        region.span.latitudeDelta = 0.02
        region.span.longitudeDelta = 0.02
 
        mapView.setRegion(region,animated:true)
```

また、mapView.selectAnnotationとすると引数で渡したピンのコールアウトを表示します。

![SimpleMap.png](https://qiita-image-store.s3.amazonaws.com/0/5247/132e8254-62c7-5e58-2db2-0dc24979e2ad.png "SimpleMap.png")



# 参考
* [Swift と MapKit で地図アプリを作成する（前編） \- koogawa log](http://blog.koogawa.com/entry/2015/11/01/024007)
* [【Tips】iOSで位置情報を取得する方法（Swift 3\.0対応） \- koogawa log](http://blog.koogawa.com/entry/2016/03/26/181906)
* [\[iOS\] 位置情報の取得 ｜ Developers\.IO](http://dev.classmethod.jp/smartphone/ios-locationmanager/)
* [MKMapViewのピンをタッチせずにコールアウトを出す](http://d.hatena.ne.jp/shu223/20110325/1301709495)
* [\[iPhone\] MapKitを使って地図を表示 \| iPhoneアプリ開発](https://iphone-app-tec.com/ios/mapview.html)