Upgrade to Pro — share decks privately, control downloads, hide ads and more …

無料で使えて意外と凄いMapKitの世界

 無料で使えて意外と凄いMapKitの世界

iOSDC Japan 2023 -DAY1-(ルーキーズLT)
https://fortee.jp/iosdc-japan-2023/proposal/b65bd1c5-1a4b-4e84-bda3-1a2b86a11cfa

【無料で使えて意外と凄いMapKitの世界】
Apple標準フレームワークでお馴染み「MapKit」ですが、
「ただ地図にピンを立てるだけ」ではなく様々な機能がいくつもあることを、みなさん知っていますか?

実はMapKitには毎年新機能が追加され、年々出来ることも増えてきています。
・スポット名での検索&サジェスト
・A地点からB地点への経路探索
・緯度経度と住所の相互変換(ジオコーディング)
・ピンのカスタマイズやクラスタリング
・地図上のスポットアイコン(POI)のフィルタリング
・マップ上への図形の描画
など、このLTでは実際にプロダクトに導入した経験も踏まえ、
MapKitを使い無料で実現できる様々なカスタマイズや機能についてご紹介します!

saikei (Keisuke Saito)

September 02, 2023
Tweet

More Decks by saikei (Keisuke Saito)

Other Decks in Programming

Transcript

  1. ॅॴͱҢ౓ܦ౓ͷ૬ޓม׵ ʢδΦίʔσΟϯάͱٯδΦίʔσΟϯάʣ ॅॴ FY౦ژ౎৽॓۠େٱอ Ң౓ܦ౓ FY    $-(FPDPEFS

    J04 // 住所 → 緯度経度(を含むCLPlacemark) let address = "東京都新宿区大久保3-4-1" let placemarks: [CLPlacemark] = try await CLGeocoder().geocodeAddressString(address) // 緯度経度 → 住所(を含むCLPlacemark) let location = CLLocation(latitude: 35.70620, longitude: 139.70713) let placemarks: [CLPlacemark] = try await CLGeocoder().reverseGeocodeLocation(location) 🙋ॴଐ͸ʮχϑςΟϥΠϑελΠϧגࣜձࣾγεςϜ։ൃ෦ΞϓϦ։ൃνʔϜʯͰ͢ʂ
  2. Ξϊςʔγϣϯʢϐϯʣ Λ஍ਤʹࢗ͢ J04 🙋ฐࣾ͸ࠓ೥΋J04%$ͷεϙϯαʔΛ͍ͯ͠·͢ʂ let annotation = MKPointAnnotation() annotation.title =

    “早稲田大学" // タイトル(任意) annotation.subtitle = "西早稲田キャンパス" // タイトル(任意) annotation.coordinate = CLLocationCoordinate2D( /* 西早稲田駅 */ ) self.mapView.addAnnotation(annotation)
  3. Ξϊςʔγϣϯʢϐϯʣ Λ஍ਤʹࢗ͢ J04 let annotation = MKPointAnnotation() annotation.title = “早稲田大学"

    // タイトル(任意) annotation.subtitle = "西早稲田キャンパス" // タイトル(任意) annotation.coordinate = CLLocationCoordinate2D( /* 西早稲田駅 */ ) self.mapView.addAnnotation(annotation) func mapView( _ mapView: MKMapView, viewFor annotation: MKAnnotation ) -> MKAnnotationView? { let annotationView = mapView.dequeueReusableAnnotationView( withIdentifier: MKMapViewDefaultAnnotationViewReuseIdentifier, for: annotation ) as! MKMarkerAnnotationView annotationView.clusteringIdentifier = "group1" return annotationView } ΫϥελϦϯάʹରԠͤ͞Δ 🙋ฐࣾ͸ࠓ೥΋J04%$ͷεϙϯαʔΛ͍ͯ͠·͢ʂ
  4. εϙοτʢ৔ॴʣݕࡧ Ωʔϫʔυ FYϨετϥϯ ʢ˞ج४஍఺͸೚ҙͰઃఆՄʣ .,-PDBM4FBSDI$PNQMFUFS J04 let searchCompleter = MKLocalSearchCompleter()

    searchCompleter.delegate = self searchCompleter.queryFragment = "レストラン" searchCompleter.region = MKCoordinateRegion(/* 西早稲田駅 */) // 検索結果は ` MKLocalSearchCompleterDelegate` で受け取る func completerDidUpdateResults(_ completer: MKLocalSearchCompleter) { print("result:\(completer.results)") // -> [MKLocalSearchCompletion] } 🙋໌೔ʢ%":ʣͷʲʙʳ5SBDL$Ͱεϙϯαʔηογϣϯ΋ొஃ͠·͢ʂ
  5. Ϛοϓ΁ͷਤܗͷΦʔόʔϨΠʢඳըʣ 📝7JFX$POUSPMMFS J04 📝.,.BQ7JFX%FMFHBUF let coordinates: [CLLocationCoordinate2D] = [ .init(latitude:

    35.70620, longitude: 139.70713), // 四角形の4点を緯度経度で指定 ] let polygon = MKPolygon( coordinates: coordinates1, count: coordinates1.count ) mapView.addOverlay(polygon1) func mapView( _ mapView: MKMapView, rendererFor overlay: MKOverlay ) -> MKOverlayRenderer { let polygon = overlay as! MKPolygon let polygonRenderer = MKPolygonRenderer(polygon: polygon) polygonRenderer.strokeColor = .systemRed // 枠の色 polygonRenderer.lineWidth = 2.0 // 枠の太さ polygonRenderer.fillColor = .green // 塗りの色 polygonRenderer.alpha = 0.5 // 透明度 return polygonRenderer } ਤܗͷ௖఺ΛҢ౓ܦ౓Ͱࢦఆ .BQ7JFXʹBEE0WFSMBZ͢Δ ਤܗͷσβΠϯ͸ .,.BQ7JFX%FMFHBUFଆͰࢦఆ 🙋Α͚Ε͹εϙϯαʔηογϣϯ΋ݟʹ͖͍ͯͩ͘͞ʂ
  6. ܦ࿏୳ࡧ ࢝఺ɾऴ఺ FYʮ੢ૣҴాӺʯ͔Β ʮձ৔ೖΓޱʯ·Ͱ J04 let request = MKDirections.Request() request.source

    = MKMapItem(placemark: MKPlacemark(coordinate: /* 西早稲田駅 */ )) // 始点緯度経度 request.destination = MKMapItem(placemark: MKPlacemark(coordinate: /* 会場入り口 */ )) // 終点緯度経度 request.transportType = .walking // 移動手段: MKDirectionsTransportType(徒歩、自動車、公共交通機関、全て) let response: MKDirections.Response = try await MKDirections(request: request).calculate() print(response.routes) // -> [MKRoute] 🙋ීஈ͸ϖϯϥΠτৼΔଆͷੜ׆Λ͍ͯ͠ΔΜͰ͕͢ʜ .,%JSFDUJPOT
  7. Ϛοϓཁૉʢ10*ʣ ͷϑΟϧλϦϯά σϑΥϧτ J04 ੾Γସ͑ͷ༷ࢠ let filter = MKPointOfInterestFilter(including: [.cafe,

    .restaurant]) let mapConfiguration = MKStandardMapConfiguration() mapConfiguration.pointOfInterestFilter = filter self.mapView.preferredConfiguration = mapConfiguration 🙋ϖϯϥΠτΛৼΒΕΔଆͷޫܠ΋ѱ͘ͳ͍Ͱ͢Ͷʂਪ͕͠ݟͯΔੈքʂ .,1PJOU0G*OUFSFTU'JMUFS
  8. Ϛοϓཁૉʢ10*ʣ ͷ৘ใऔಘ J04 // λοϓՄೳͳཁૉΛࢦఆ mapView.selectableMapFeatures = [.pointsOfInterest, .physicalFeatures, .territories]

    // λοϓΠϕϯτ͸௨ৗͷΞϊςʔγϣϯͱಉ༷ `MKMapViewDelegate` Ͱड͚औΔ func mapView(_ mapView: MKMapView, didSelect annotation: MKAnnotation) { guard let featureAnnotation = annotation as? MKMapFeatureAnnotation else { return } let featureRequest = MKMapItemRequest(mapFeatureAnnotation: featureAnnotation) Task { let featureMapItem: MKMapItem = try await featureRequest.mapItem print(featureMapItem.name ?? "nil") // => 早稲田大学 西早稲田キャンパス print(featureMapItem.phoneNumber ?? "nil") // => +81 3 3203 4333 print(featureMapItem.url?.absoluteString ?? "nil") // => https://www.waseda.jp/top/ } } TFMFDUBCMF.BQ'FBUVSFTΛࢦఆ .,.BQ7JFX%FMFHBUFͰλοϓΛड͚औΔ .,.BQ*UFN3FRVFTUʹ౉͢ͱʮి࿩൪߸ʯ ΍ʮαΠτͷ63-ʯ͕ฦ٫͞ΕΔ 🙋GPSUFFͰͷϑΟʔυόοΫ΋͓଴ͪͯ͠·͢ʂ
  9. Ξϊςʔγϣϯʢϐϯʣ ͷΧελϚΠζ J04 ᶃ.,1PJOU"OOPUBUJPO wΞϊςʔγϣϯࣗମͷ৘ใΛ ࣋ͭΫϥε w஍ਤ্ʹ഑ஔ͢Δͷʹ࢖༻͢ Δ ᶄ.,"OOPUBUJPO7JFX wΞϊςʔγϣϯͷ7JFXΛ࣋ͭ

    Ϋϥε w.BQ7JFX%FMFHBUF಺Ͱᶃͷ Ξϊςʔγϣϯʹରͯ͠7JFXΛ ࢦఆ͢Δ "QQFOEJY // マップ上に表示するアノテーションの指定 let location = CLLocationCoordinate2D(latitude: 35.70620, longitude: 139.70713) let annotation = CustomAnnotation() annotation.coordinate = location mapView.addAnnotation(annotation) // カスタマイズアノテーション & アノテーションView class CustomAnnotation: MKPointAnnotation {} // アノテーションの情報(空でも可) class CustomAnnotationView: MKAnnotationView {} // 実際のアノテーションのView(xibでの実装も可) // ` MapViewDelegate` でアノテーションに対するアノテーションViewを指定する func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? { switch annotation { case is CustomAnnotation: // CustomAnnotationで作成されたアノテーション let customAnnotationView = CustomAnnotationView() return customAnnotationView case let annotation as MKClusterAnnotation: // クラスタリングされたアノテーション let clusteringCustomAnnotationView = ClusteringCustomAnnotationView() // クラスタリングされているアノテーションの情報は ` annotation.memberAnnotations` で取得可 // ` ClusteringCustomAnnotationView` のプロパティに渡すことで表示を切り替えられる return customAnnotationView } }
  10. BJSQPSU ʢۭߓʣ BNVTFNFOU1BSL ʢ༡Ԃ஍ʣ BRVBSJVN ʢਫ଒ؗʣ BUN ʢ"5.ʣ CBLFSZ ʢύϯ԰ʣ

    CBOL ʢۜߦʣ CFBDI ʢϏʔνʣ CSFXFSZ ʢৢ଄ॴʣ DBGF ʢΧϑΣʣ DBNQHSPVOE ʢΩϟϯϓ৔ʣ DBS3FOUBM ʢϨϯλΧʔʣ FW$IBSHFS ʢ&7ॆిثʣ fi SF4UBUJPO ʢফ๷ॺʣ fi UOFTT$FOUFS ʢδϜʣ GPPE.BSLFU ʢ৯ྉ඼ళʣ HBT4UBUJPO ʢΨιϦϯελϯυʣ IPTQJUBM ʢපӃʣ IPUFM ʢϗςϧʣ MBVOESZ ʢΫϦʔχϯά԰ʣ MJCSBSZ ʢਤॻؗʣ NBSJOB ʢߓʣ NPWJF5IFBUFS ʢөըؗʣ NVTFVN ʢത෺ؗʣ OBUJPOBM1BSL ʢࠃཱެԂʣ OJHIUMJGF ʢόʔͳͲʣ QBSL ʢެԂʣ QBSLJOH ʢறं৔ʣ QIBSNBDZ ʢༀہʣ QPMJDF ʢܯ࡯ॺʣ QPTU0 ff i DF ʢ༣ศہʣ QVCMJD5SBOTQPSU ʢެڞަ௨ػؔʣ SFTUBVSBOU ʢϨετϥϯʣ SFTUSPPN ʢτΠϨʣ TDIPPM ʢֶߍʣ TUBEJVN ʢελδΞϜʣ TUPSF ʢ͓ళʣ UIFBUFS ʢܶ৔ʣ VOJWFSTJUZ ʢେֶʣ XJOFSZ ʢϫΠφϦʔʣ [PP ʢಈ෺Ԃʣ શछྨ 10*ͷΧςΰϦʔʢ.,1PJOU0G*OUFSFTU$BUFHPSZʣ "QQFOEJY