MkMapViewを使って地図系アプリを作っているのですが、意外にまとまった情報がありませんでした。そこで簡単な地図アプリ作成手順として情報を整理しました。
作成したアプリは、Githubに置いています。
機能
以下の機能を実装しました。
- 現在位置を地図上に表示できる
- 緯度経度をラベル表示できる
- 現在位置のトラッキングを開始・終了できる
- 地図のスケールを自動的に調整できる
- 現在位置にピンをつけることができる
- ピンのコールアウトをタップしないで表示する
アプリ作成手順
- プロジェクト作成
- アプリで位置情報を使うための設定
- 位置情報取得処理追加
- ピン表示処理追加
プロジェクト作成
ここを参考にして、プロジェクトを作成します。
- Single View Applicationを選択してプロジェクトを作成します。
- 地図ライブラリ(MapKit.framework)を追加します。
- Storyboardを使ってMap Kit Viewを追加します。
位置情報表示のためのラベルと位置情報取得開始・終了用ボタンを追加しています。
アプリで位置情報を使うための設定
位置情報を使うための以下のキーをinfo.plistに追加します。
- Privacy - Location When In Use Usage Description
- Privacy - Location Always Usage Description
アプリ初回起動時にユーザーに許可を出す時のメッセージになります。
// 位置情報取得時に、リクエストを出すと
locationManager!.requestWhenInUseAuthorization()
// このメソッドが呼ばれます
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
switch status {
case .notDetermined:
manager.requestWhenInUseAuthorization()
case .restricted, .denied:
break
case .authorizedAlways, .authorizedWhenInUse:
break
}
}
位置情報取得処理追加
CLLocationManagerクラスを使って位置情報の取得します。
開始
startUpdatingLocationを実行します。
位置情報が更新された場合には、CLLocationManagerDelegateプロトコルのlocationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation])が呼ばれます。
@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を実行します。
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クラスを使います。
現在位置を一つだけ表示するために、全削除して追加しています。
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)
開始ボタンタップする前
全部のピンを表示してくれます。
開始ボタンをタップ時にmapView.showAnnotationsを実行するとすべてのピンが表示されます。
mapView.setRegionを使ってズーム率を指定することができます。
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とすると引数で渡したピンのコールアウトを表示します。