LoginSignup
4
3

More than 1 year has passed since last update.

MKTileOverlayを用いてMKMapViewにタイルを表示する

Last updated at Posted at 2021-12-14

はじめに

※この記事はLIFULL Advent Calendar 2021の15日目の記事となります。
※2日目に投稿したけど、まだ空いていたのでまた投稿しちゃいます。

MapKitでピンを立てたりルートを表示したりすることはあったけど、MKTileOverlayを使ってタイルを表示させることはなかったので、大きく二種類の方法があったので今回やってみたという記事です。

サーバ上にあるタイル情報を用いる場合

使用する情報

今回はよく検索にもヒットする**国土地理院**のデータを利用します。

注意点としては以下があります。

地理院タイルをウェブサイトやソフトウェア、アプリケーション上でリアルタイムに読み込んで利用する場合、地理院タイルは出典の明示のみで申請不要でご利用いただけます。

アプリ開発で使う場合は出典を明示しておきましょう。

実装

StoryBoard上にMKMapViewが既に配置されている前提とします。

// 国土地理院のデータから、今回は「淡色地図」タイルを利用する
let overlay = MKTileOverlay.init(urlTemplate:"https://cyberjapandata.gsi.go.jp/xyz/pale/{z}/{x}/{y}.png")

// MKMapView にオーバーレイを追加する    
mapView.addOverlay(overlay)

これだけだとマップに変化はありません。
MKMapViewDelegateのrendererForメソッドを実装する必要があります。

extension HogeViewController: MKMapViewDelegate {
    func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
        return MKTileOverlayRenderer.init(overlay: overlay)
    }
}

##結果
オーバーレイを追加したことで右画像のように淡色地図が表示されます。
他にも国土地理院のデータでは航空写真や活断層図等、さまざまなデータが用意されています。

標準地図 淡色地図
標準地図.png 単色地図.png

カスタムのタイル情報を用いる場合

タイルを表示する方法は先ほど実現した、国土地理院や他のサイトで公開されているデータを用いるか、自作のAPIからタイル情報を受けとってその情報をもとにカスタムな表示をするのどちらかに分かれるかと思います。
後者ではMKTileOverlayloadTile()メソッドを用いて実現します。

今回は、タイルの座標によって赤、青、緑のいずれかのタイルを重ねるようにしてみます。

実装

まずはMKTileOverlayを継承したカスタムクラスを定義します。
このクラスでloadTile()メソッドをオーバーライドします。

CustomTileOverlay.swift
import UIKit
import MapKit

class CustomTileOverlay: MKTileOverlay {

    override func loadTile(at path:MKTileOverlayPath, result:@escaping (Data?, Error?) -> Void) {
        UIGraphicsBeginImageContext(CGSize(width: 256,height: 256))

        guard let context = UIGraphicsGetCurrentContext() else {
            return
        }

        let r: CGFloat = ((path.x + path.y) % 3) == 0 ? 1 : 0
        let g: CGFloat = ((path.x + path.y + 1) % 3) == 0 ? 1 : 0
        let b: CGFloat = ((path.x + path.y + 2) % 3) == 0 ? 1 : 0
        let alpha: CGFloat = 0.5;
        let fill = CGColor(red: r, green: g, blue: b, alpha: alpha)

        context.setFillColor(fill)
        context.fill(CGRect(x: 0, y: 0, width: 256,height: 256))

        let tileImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        result(tileImage?.pngData(), nil)
    }
}

国土地理院のデータを扱っていた箇所を今回のオーバーレイを使うように書き換えてみましょう。
一行変更するだけで問題ありません。

// 国土地理院のデータを扱う場合
// let overlay = MKTileOverlay.init(urlTemplate:"https://cyberjapandata.gsi.go.jp/xyz/pale/{z}/{x}/{y}.png")

// 今回作成したOverlayを呼び出す
let overlay = CustomTileOverlay()

// そのまま
mapView.addOverlay(overlay)

##結果
見事チェック模様にタイルが表示されるようになりましたね。
チェックタイル.png

おまけ:特定の位置だけタイルを表示してみる

上記の例から、ある特定の場所だけにタイルを表示するような処理に書き換えてみます。
loadTileメソッドの引数にあるpath: MKTileOverlayx、y、zというプロパティを持っています。
xとyはタイルを表示するためのx座標とy座標を表し、zは地図のズームレベルを表します。

今回は直撃ちで、x=116397、y=51624、z=17を指定してみます。

CustomTileOverlay.swift
override func loadTile(at path:MKTileOverlayPath, result:@escaping (Data?, Error?) -> Void) {
        UIGraphicsBeginImageContext(CGSize(width: 256,height: 256))

        guard
            let context = UIGraphicsGetCurrentContext(),
            path.x == 116397,
            path.y == 51624,
            path.z == 17 else {
                return
            }

        // 以降は同じ
    }

これで実行すると、渋谷付近にタイルが表示されるのを確認できました。
ちなみにズームレベルが17で指定しているので、このズームレベルよりも大きくても小さくても表示されません。
特定位置地図.png

終わりに

普段触らないタイル表示は数行で実現はできるものでした。
後者のカスタムな表示方法は、独自のAPIを用意できると、より個人開発で活用できそうだなと思いました。

API開発のスキルは現在磨き中なので、自前でできるようにして色々遊べるようになりたい。。

参照

  1. 国土地理院
  2. MKMapView の地図タイルをオーバーレイする
  3. SwiftUIでカスタム地図を表示する(その2) - Blogger
  4. loadTile(at:result:) | Apple Developer Documentation
4
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
3