Edited at

Swift MkMapViewで地図アプリ作成してみた(14)final - iOSでロングタップした位置をwatchOSが受信して現在位置との距離を表示する


記事一覧

Swift MkMapViewで地図アプリ作成してみた(記事一覧)


iOSのアプリから取得した緯度経度を保持する


iOSのアプリでロングタップした位置をwatchOSに送信する

sendMessageでwatchOSにロングタップした位置を送信する方法は以下の記事を参照ください。


受信した緯度経度を保持する

クラスのメンバ変数に緯度経度を追加し、iOSからsendMessageで送信された緯度経度を変数に設定する。


InterfaceController.swift:緯度経度の変数を追加

class InterfaceController:  WKInterfaceController,

WCSessionDelegate { // sasaki
var dlon:Double! = 0
var dlat:Double! = 0


InterfaceController.swift:iOSからsendMessageで送信された緯度経度を変数に設定

    // iPhoneからMessage受信

public func session(_ session: WCSession, didReceiveMessage message: [String : Any], replyHandler: @escaping ([String : Any]) -> Swift.Void){
print("receiveMessage::\(message)")

guard let lon = message["lon"] as? Double else {
return
}

guard let lat = message["lat"] as? Double else {
return
}

// iOSからsendMessageで送信された緯度経度を変数に設定
dlon = lon
dlat = lat
}



CLLocationManagerで現在位置を取得する


CLLocationManagerのdelegateを登録する

CoreLocationをimportし、CLLocationManagerDelegateを継承する。

現在位置取得に必要なCLLocationManagerの変数を定義する。


InterfaceController.swift

import CoreLocation

class InterfaceController: WKInterfaceController,
WCSessionDelegate,
CLLocationManagerDelegate {
var dlon:Double! = 0
var dlat:Double! = 0
var locationManager = CLLocationManager()


Initializerメソッドで、CLLocationManagerのdelegateを登録する。


InterfaceController.swift

    override init() {

super.init()

// CLLocationManagerのdelegateを登録
locationManager.delegate = self
}



CLLocationManagerで現在位置の更新を受信する

以下の条件を満たしている場合に、startUpdatingLocationメソッドで現在位置の更新を開始できる。


  • locationServicesEnabledメソッドで端末の位置情報サービスが有効である

  • authorizationStatusメソッドでユーザから位置情報利用の許可を一度得ている


InterfaceController.swift

    override init() {

super.init()

// CLLocationManagerのdelegateを登録
locationManager.delegate = self

// 端末の位置情報サービスが有効である
if CLLocationManager.locationServicesEnabled() {
switch CLLocationManager.authorizationStatus() {
// ユーザから位置情報利用の許可を一度得ている
case .authorizedAlways, .authorizedWhenInUse:
// 現在位置の更新を開始
locationManager.startUpdatingLocation()
case .notDetermined:
print("notDetermined")
case .restricted:
print("restricted")
case .denied:
print("denied")
}
}
}


locationManagerメソッドを定義すると、現在位置の更新を受信できる。


InterfaceController.swift

    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {

print(Date(), locations)
}



現在位置更新を受信した時にiOSから受信した位置との距離を表示する


2点間の距離(m)を算出するメソッドを作成する

引数に現在位置を指定して、クラスのメンバ変数に設定したiOSから受信した緯度経度との距離(m)を算出するメソッドを作成する。


InterfaceController.swift

    func calcDistance(_ a: CLLocationCoordinate2D) -> CLLocationDistance {

// CLLocationオブジェクトを生成
let aLoc: CLLocation = CLLocation(latitude: a.latitude, longitude: a.longitude)
let cloclon:CLLocationDegrees = CLLocationDegrees(exactly: dlon)!
let cloclat:CLLocationDegrees = CLLocationDegrees(exactly: dlat)!
let bLoc: CLLocation = CLLocation(latitude: cloclat, longitude: cloclon)
// CLLocationオブジェクトのdistanceで2点間の距離(m)を算出
let dist = bLoc.distance(from: aLoc)
return dist
}


現在位置の更新を受信した時に距離を算出してwatchOSのアプリに表示する

locationManagerメソッドで現在位置の更新を受信した時に、iOSから受信した緯度経度との距離(m)を算出して表示する。


InterfaceController.swift

    // CLLocationManagerのdelegate:現在位置更新

func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {

print(Date(), locations)

// iOSから緯度経度を受信している場合
if dlon != 0 && dlat != 0 {
// 現在位置とiOSから受信した緯度経度との距離(m)を算出する
let distance = calcDistance((locations.last?.coordinate)!)
// mをyardに変換する
let yardStr = Int(distance * 1.09361)
// 距離をラベルのテキストに設定する
let fontSize = UIFont.systemFont(ofSize: 45)
let text = String(Int(distance).description + "m" + "\n" + yardStr.description + "y")
let attrStr = NSAttributedString(string: text, attributes:[NSAttributedString.Key.font:fontSize])
label.setAttributedText(attrStr)
}
}



iOSから緯度経度を受信した時にも現在位置との距離を表示する


現在位置をクラスのメンバ変数に保持する

メンバ変数をCLLocationCoordinate2D型で定義する。


InterfaceController.swift

class InterfaceController:  WKInterfaceController,

WCSessionDelegate,
CLLocationManagerDelegate {
var locCord2D:CLLocationCoordinate2D?

現在位置をクラスのメンバ変数に保持する。


InterfaceController.swift

    // CLLocationManagerのdelegate:現在位置更新

func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
print(Date(), locations)

// 現在位置をクラスのメンバ変数に保持する
locCord2D = (locations.last?.coordinate)!

// iOSから緯度経度を受信している場合
if dlon != 0 && dlat != 0 {



iOSから緯度経度を受信した時にも現在位置との距離を表示する

sessionメソッドに距離を表示する処理を追加する。


InterfaceController.swift

    // iPhoneからMessage受信

public func session(_ session: WCSession, didReceiveMessage message: [String : Any], replyHandler: @escaping ([String : Any]) -> Swift.Void){
print("receiveMessage::\(message)")

guard let lon = message["lon"] as? Double else {
return
}

guard let lat = message["lat"] as? Double else {
return
}

// iOSからsendMessageで送信された緯度経度を変数に設定
dlon = lon
dlat = lat

// iOSから緯度経度を受信した時にも現在位置との距離を表示する
if nil != locCord2D {
// 現在位置とiOSから受信した緯度経度との距離(m)を算出する
let distance = calcDistance(locCord2D!)
// mをyardに変換する
let yardStr = Int(distance * 1.09361)
// 距離をラベルのテキストに設定する
let fontSize = UIFont.systemFont(ofSize: 45)
let text = String(Int(distance).description + "m" + "\n" + yardStr.description + "y")
let attrStr = NSAttributedString(string: text, attributes:[NSAttributedString.Key.font:fontSize])
label.setAttributedText(attrStr)
}
}


image1.png


記事一覧

Swift MkMapViewで地図アプリ作成してみた(記事一覧)