Help us understand the problem. What is going on with this article?

iOS 13でMapKitに新しく追加されたPOI(Point of Interest)フィルタリングを触ってみる

はじめに

WWDC19で発表された内容が濃すぎて,
調べて使ってみたいけど扱えていない内容がまだまだたくさんです😅

今回はそのひとつで iOS 13 から新しく MapKit に追加され
Point of Interest(POI) フィルタリングを触ってみました。

このセッションの短い時間ではありましたが紹介されています。(10分あたりから)
What’s New in MapKit and MapKit JS
https://developer.apple.com/videos/play/wwdc2019/236/

MapKit における POI とは

MapKit における POI とは Map に表示されている,
レストランとか学校など様々な場所表示です。それぞれアイコンもあります。
言われてみればあーあれかってなりますよね。
スクリーンショット 2019-12-23 18.22.04.png
種類的には,執筆時点で 40種類あります。(セッション資料より)
Apple Park みたいな特別な場所は専用のものが用意されているようです。
スクリーンショット 2019-12-23 18.22.04.png
MapKit チームはデベロッパにもっとこういうのあったらどうか?と
ユースケースや提案があれば是非頼むというスタンスのようです。

参考:MKPointOfInterestCategory
https://developer.apple.com/documentation/mapkit/mkpointofinterestcategory?language=swift

iOS 12 までの POI のフィルタリング

通常の Map アプリでは情報が多くてもいいと思います。
都市部だと明らかにアイコンの乱立がありユーザの目移りが問題になります。
それぞれのアプリの Map の用途によって
POI のフィルタリング(出し分け)ができるとアプリの UX が上がりそうです。

iOS 12 までは,POI の全表示 or 全非表示はできていました。
MapView の showsPointsOfInterest に Bool 値を与えていました。
コードは下記です。

let mapView = MKMapView()
mapView.showsPointsOfInterest = false

こんな感じで POI が非表示になります。全部非表示にはならないんだなぁ。
純正 Map 自体も更新されているだろうし,APIの方がついていってない感じ。

デフォルト 設定OFF
IMG_1919.PNG IMG_1920.PNG

参考:showsPointsOfInterest
https://developer.apple.com/documentation/mapkit/mkmapview/1452102-showspointsofinterest?language=swift

iOS 13 以降の POI フィルタリング

今までは,POI を全表示 or 全非表示しかできなかったですが,
iOS 13 からフィルタリングが可能になりました。

showsPointsOfInterest
iOS 13 以降では,レファレンスの通り Deprecated になっています。
代わりに pointOfInterestFilter を使うように変わっています。

参考:pointOfInterestFilter
https://developer.apple.com/documentation/mapkit/mkmapview/3143417-pointofinterestfilter?language=swift

pointOfInterestFilter を使って,POI のフィルタリングができます。
前述した MKPointOfInterestCategory が出し分けとして利用されます。

以下 3種類の POI フィルタリングを紹介します。

都合によりスクショを貼っていますが,
マップの拡大・縮小を行なっても設定は維持されます。

この POI だけ表示したい,ケース

POI が多いので レストランやカフェ,フードマーケットだけ表示させたいなぁ〜
そういう場合は,MKPointOfInterestCategory を格納する Array を用意して,
レストランとカフェ,フードマーケットをフィルタリングします。
include なので直感的でわかりやすいですね。

let category: [MKPointOfInterestCategory] = [.restaurant, .cafe, .foodMarket]
let filter = MKPointOfInterestFilter(including: category)
mapView.pointOfInterestFilter = filter

実行結果はこちらです。まだ多い気もするけどだいぶ絞れましたね。
よく見るとデフォルトだと表示されないレストランも表示されています。
これでレストラン探しが捗りそうな気がしますね!

デフォルト フィルタリング後
IMG_0521.PNG IMG_0523.PNG

この POI だけ表示したくない,ケース

逆に飲食店を非表示にしたいなぁ〜 みたいなケースがあったとしましょう。

逆に exclude で該当のカテゴリのみ非表示にできます。

let category: [MKPointOfInterestCategory] = [.restaurant, .foodMarket, .cafe]
let filter = MKPointOfInterestFilter(excluding: category)
mapView.pointOfInterestFilter = filter

こちらも飲食店が非表示になって表示されるようになったお店などがあります。

デフォルト フィルタリング後
IMG_0521.PNG IMG_0524.PNG

全部表示しない,ケース

該当のアノテーション以外の情報はいらないんや〜
という場合は excludingAll を使います。

let filter = MKPointOfInterestFilter.excludingAll
mapView.pointOfInterestFilter = filter

結果は下記です(左側)。
今までの showsPointsOfInterestfalse のときよりも POI が消えてますね。
あまりないケースとは思います。

[新]全て非表示 [旧]全て非表示
IMG_1920.PNG IMG_1920.PNG

具体的なユースケース(妄想)🤔

POIのフィルタリングはむやみに設定するものではなく,
アプリを利用するユーザのことを意識して行うべきです。
何個か妄想してみました。

例1

例えば,飲食店のアプリでお店の場所を示すのに住所と Map を掲載するとします。
お店に駐車場がないので周りのコインパーキングなどを利用してほしいとします。
この場合,駐車場のアイコンだけを表示するようにすると
ユーザは他のロケーションに目移りせずに駐車場の位置を意識できます。

let category: [MKPointOfInterestCategory] = [.parking]]
let filter = MKPointOfInterestFilter(including: category)
mapView.pointOfInterestFilter = filter
フィルタリング前 フィルタリング後
IMG_0526.PNG IMG_0525.PNG

例2

つぎは海外カンファレンスなどのイベント系アプリを考えてみます。
同じく会場の場所を示すのに住所と Map を掲載するとします。
世界各国のデベロッパが会場のある街(都市,国)に訪れます。
ユーザが気になるのは会場近くのレストラン,ホテル,駅なのではないでしょうか?
あるいは観光する人もいるかもしれません。

let category: [MKPointOfInterestCategory]
    = [.hotel,
       .restaurant, .cafe,
       .airport, .publicTransport,
       .beach, .amusementPark, .nightlife]
let filter = MKPointOfInterestFilter(including: category)
mapView.pointOfInterestFilter = filter
フィルタリング前 フィルタリング後
IMG_0527.PNG IMG_0528.PNG

うーんイマイチかな。マップ拡大しないと恩恵少ない。
WWDC は会場から近いホテルがおすすめです。(私はフェアモント派)
VTA ライトレール使えるので駅近もいいですね。
現地では,体調第一でいろいろ決めると良いです。時差もありますしね。
来年も行きたいなぁ🤩

SwiftUI でも使える

SwiftUI でも MapKit を使っているので,書き方はほぼ同じです。
SwiftUI での MapView の使い方の復習と
POIフィルタリングを記事にしようと思っていたのですが計画狂っちゃいました。

ContentView.swift
import SwiftUI
struct ContentView: View {
    var body: some View {
        ScrollView {
            VStack(alignment: .leading) {
                // MapView Part
                MapView()
                    .frame(height: 300.0)
                // 省略
            }
        }
    }
}

UIViewRepresentable に準拠させます。
makeUIView 関数内で frame のコード書いても無視されるっぽくて
初期化する View で設定するとちゃんと意図通りに動くようです。

MapView.swift
import SwiftUI
import MapKit    // これが必須

struct MapView: UIViewRepresentable {

    func makeUIView(context: Context) -> MKMapView {
        let mapView = MKMapView(frame: .zero)
        return mapView
    }

    // Required
    func updateUIView(_ uiView: MKMapView, context: UIViewRepresentableContext<MapView>) {
        let center = CLLocationCoordinate2DMake(緯度, 経度)
        let span = MKCoordinateSpan(latitudeDelta: 0.002, longitudeDelta: 0.002)
        let region = MKCoordinateRegion(center: center, span: span)
        uiView.setRegion(region, animated: true)

        // POIフィルタリング(UIKitと使い方は変わらない)
        let category: [MKPointOfInterestCategory] = [.parking, .publicTransport]
        let filter = MKPointOfInterestFilter(including: category)
        uiView.pointOfInterestFilter = filter

        // アノテーションを表示
        let annotation = MKPointAnnotation()
        annotation.coordinate = center
        annotation.title = "アノテーションタイトル"
        uiView.addAnnotation(annotation)
    }
}

Enjoy SwiftUI vol2 でライブコーディングした
サンプルアプリのイベント詳細画面を更新してみました。
フィルタリングは [.parking, .publicTransport] にしています。
駐車場や駅の情報が確認できますね。

RPReplay_Final1577104328.gif

サンプルコードはこちらです。
https://github.com/MilanistaDev/StudyGroupEventFetcherForSwiftUI

connpass の API 叩いてリストに表示する部分の記事もよろしければご覧ください。
【SwiftUI】外部APIを叩いて取得した結果をListに表示する
https://qiita.com/MilanistaDev/items/64dca8c9d5099a19529e

おわりに

今回は,iOS 13 の Mapkit に新しく追加された
POI のフィルタリングについて書きました。

頭の片隅に置いて,これからは Map を実装する際は,
Map 上の POI のことを少し意識してみてはいかがでしょうか?
ユーザの目線で考えることが大事です。

ご覧いただきありがとうございました!

今年も多くの方に支えられて楽しく1年過ごすことができました。
来年も引き続きアウトプット駆動で精進していこうと思っておリます!

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした