質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

87.79%

[swift] 地図上のアノテーションをタップしたときUILabelを表示する方法

解決済

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 2,920

score 12

前提・実現したいこと

iOSアプリを作成しています。
ライブハウスの名前を検索して地図上に周辺のコインロッカーを表示させるアプリです。
場所の情報(latitude,longitude,keyword)をJSON形式で取得し、地図上に該当の場所のAnnotationを表示することまではできました。
最初は吹き出しで詳細情報(keyword)を表示しようとしていましたが、文字列が長い場所もあるので、グーグルマップのように、アノテーションをタップすると画面下部からラベルが出てくるようにしたいのですが、どう書いて良いのかわかりません。

func mapView(myMapView: MKMapView, didSelectAnnotationView view:MKAnnotationView)
がアノテーションが選択されたときのメソッドだということまではわかりました。

発生している問題・エラーメッセージ

わからないのは
① searchLockerメソッドのfor文の中でJSONデータから取り出したkeywordはローカル変数です。
どうやって上記のmapViewメソッドに渡すのか。

②アノテーションの場所によってkeywordの内容も異なります。アノテーションの識別とkeywordの紐付けが行われないと正しい場所に正しいkeywordが表示されないと思うのですが、アノテーションを区別する方法がわかりません。

import UIKit
import MapKit
import SafariServices

class ViewController: UIViewController, UITextFieldDelegate, MKMapViewDelegate {
    @IBOutlet weak var mapView: MKMapView!
    @IBOutlet weak var inputText: UITextField!

    var locationManager: CLLocationManager?
    var numberTitle : [(number: Int, title: String)] = []
    var number = 0

    override func viewDidLoad() {
        super.viewDidLoad()

        //マップ関連の初期化処理
        self.mapView.delegate = self
        //テキストフィールドのデリゲート通知先を設定
        inputText.delegate = self
        //スイッチは最初オフにしておく
        swi.isOn = false
        swi.thumbTintColor = UIColor.yellow
        //プレースホルダーを設定
        inputText.placeholder = "ライブハウス名を入力してください"
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }

    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        //キーボードを閉じる
        textField.resignFirstResponder()

        //入力された文字を取り出す
        if let searchKey = textField.text {

            //CLGeocoderインスタンスを取得
            let geocoder = CLGeocoder()

            //入力された文字から位置情報を取得
            geocoder.geocodeAddressString(searchKey, completionHandler: { (placemarks,
                error) in

                //位置情報が存在する場合はunwrapPlacemarksに取り出す
                if let unwrapPlacemarks = placemarks {
                    //1件目の情報を取り出す
                    if let firstPlacemark = unwrapPlacemarks.first {
                        //位置情報を取り出す
                        if let location = firstPlacemark.location {
                            //位置情報から経度緯度をtargetCoordinateに取り出す
                            let targetCoordinate = location.coordinate
                            //経度緯度をデバッグに表示
                            print(targetCoordinate)

                            //MKPointAnnotationインスタンスを取得しピンを生成
                            let pin = MKPointAnnotation()
                            //ピンの置く場所に経度緯度を設定
                            pin.coordinate = targetCoordinate

                            //ピンのタイトルを設定
                            pin.title = searchKey
                            //ピンを地図に置く
                            self.mapView.addAnnotation(pin)
                            //経度緯度を中心にして半径500mの範囲を表示
                            self.mapView.region = MKCoordinateRegion(center: targetCoordinate,
                                                                     latitudinalMeters: 500.0, longitudinalMeters: 500.0)

                            //コインロッカー検索メソッド発動
                            self.searchLocker(keyword: searchKey)
                        }
                    }
                }
            })
        }
        //デフォルト動作を行うのでTRUEを返す
        return true
    }

    //jsonの中身を受け取るデータ構造
    struct Coinlocker: Codable {
        let latitude : String?
        let longitude : String?
        let keyword : String?
    }

    //ロッカーを検索するメソッド
    func searchLocker (keyword: String) {

        //検索キーワードをURLエンコードする
        guard let keyword_encode = keyword.addingPercentEncoding(withAllowedCharacters: NSCharacterSet.urlQueryAllowed) else {
            return
        }
        //リクエストURLの組み立て
        //guard let req_url = URL(string: "http://192.168.33.10:8000/api.php/?livehouse=\(keyword_encode)") else {
            return
        }
        print(req_url)

        //リクエストに必要な情報を生成
        let req = URLRequest(url: req_url)

        //データ転送を管理するためのセッションを生成
        let session = URLSession(configuration: .default, delegate: nil
            , delegateQueue: OperationQueue.main)

        //リクエストをタスクとして登録
        let task = session.dataTask(with: req, completionHandler: {
            (data , response , error) in

            //セッションを終了
            session.finishTasksAndInvalidate()

            //do try catch エラーハンドリング
            do {
                //JsonDecoderのインスタンス取得
                let decoder = JSONDecoder()
                //受け取ったJSONデータをパース(解析)して格納
                let json = try decoder.decode([Coinlocker].self, from: data!)

                //ピンを地図に表示する 取得している情報の数だけ処理
                for item in json {
                    if let latitude = item.latitude , let longitude = item.longitude , let keyword = item.keyword {
                        //String型のjsonのlatitudeとlongitudeをDoubleに変換
                        let doubleLatitude: Double = Double(latitude)!
                        let doubleLongitude: Double = Double(longitude)!
                        //マーカーを表示する
                        let ann =
                            CustomAnnotation.init(coordinate: CLLocationCoordinate2D.init(latitude: doubleLatitude,longitude: doubleLongitude), title: keyword)
                        self.mapView.addAnnotation(ann)
                    }
                }
            } catch let error {
                 print(error)
            }
        })
        //ダウンロード開始
        task.resume()
    }

    //アノテーションビューを返すメソッド
    func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {

        //ユーザの現在地の青まるはそのままなので分岐
        if(annotation is MKUserLocation) {
            return nil
        } else {
            let identifier = "Pin"
            var annotationView: MKAnnotationView? = mapView.dequeueReusableAnnotationView(withIdentifier: identifier)
            if annotationView == nil {
                annotationView = MKAnnotationView.init(annotation: annotation, reuseIdentifier: identifier)
            }
            annotationView?.image = UIImage.init(named: "icon.jpeg")
            annotationView?.annotation = annotation
            annotationView?.canShowCallout = false

            return annotationView
        }
    }

    func mapView(myMapView: MKMapView, didSelectAnnotationView view:MKAnnotationView){
        let label = UILabel(frame: CGRect(x: 40, y:0, width: 200, height: 40))
        label.numberOfLines = 0
        label.backgroundColor = UIColor.cyan
    }
}
import Foundation
import MapKit

class CustomAnnotation:NSObject, MKAnnotation {
    public var coordinate: CLLocationCoordinate2D
    public var title: String?

    init(coordinate: CLLocationCoordinate2D, title: String){
        self.coordinate = coordinate
        self.title = title

        super.init()
    }
}
[
  {
    "latitude": "35.720825",
    "longitude": "139.927428",
    "keyword": "JR本八幡駅改札付近北口方面"
  },
  {
    "latitude": "35.721100",
    "longitude": "139.927267",
    "keyword": "都営新宿線本八幡駅 地下1階 駅長事務室の左右"
  },
  {
    "latitude": "35.721180",
    "longitude": "139.926283",
    "keyword": "斉藤ビル"
  },
  {
    "latitude": "35.721445",
    "longitude": "139.927562",
    "keyword": "パティオ本八幡店 M1F踊り場"
  },
  {
    "latitude": "35.722123",
    "longitude": "139.926973",
    "keyword": "ナビパーク八幡第1駐車場"
  }
]
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

check解決した方法

0

自己解決できました。
func mapView(_ mapView: MKMapView, didSelect view:MKAnnotationView){}
の第二引数がタップされたアノテーションを受け取っていることを知りました。

func mapView(_ mapView: MKMapView, didSelect view:MKAnnotationView){
let annotation = view.annotation
let title = annotation?.title

としてアノテーションのタイトルを参照することができ、UILabelを作成しtitleを表示することができました。
お騒がせしました。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 87.79%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る