🌍
Mapkitで検索した場所を表示する
対象者
- SwiftUIに興味ある人
- Mapkit使ってる人
- 検索機能をつけたい
プロジェクトの説明
SwiftUiのMapkitを使うと、地図を表示することができます。位置を検索する機能は実装する必要がありますが.....
動作は微妙だが動くものを作ってみた。
- 実装した機能
- 画面上の検索機能
- 画面のどこかをタップすると、キーボードを閉じる
[Example Code]
import SwiftUI
import MapKit
struct ContentView: View {
@State private var searchText = ""
@State private var landmarks = [Landmark]()
var body: some View {
VStack {
// 検索バー
SearchBar(text: $searchText, onSearchButtonChanged: { self.searchLandmarks() })
// 地図表示
MapView(landmarks: $landmarks)
}
.onAppear {
// 初期表示時に東京駅を検索
searchLandmarks(for: "東京駅")
}
.onTapGesture {
// 画面をタップしたらキーボードを閉じる
UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
}
}
private func searchLandmarks(for place: String = "") {
let request = MKLocalSearch.Request()
request.naturalLanguageQuery = place.isEmpty ? searchText : place
let search = MKLocalSearch(request: request)
search.start { (response, error) in
guard let response = response else { return }
landmarks = response.mapItems.map {
Landmark(placemark: $0.placemark)
}
}
}
}
struct Landmark {
let placemark: MKPlacemark
var id: String {
placemark.name ?? UUID().uuidString
}
var name: String {
placemark.name ?? ""
}
var coordinate: CLLocationCoordinate2D {
placemark.coordinate
}
}
struct SearchBar: UIViewRepresentable {
@Binding var text: String
var onSearchButtonChanged: () -> Void
func makeUIView(context: Context) -> UISearchBar {
let searchBar = UISearchBar(frame: .zero)
searchBar.delegate = context.coordinator
return searchBar
}
func updateUIView(_ uiView: UISearchBar, context: Context) {
uiView.text = text
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
class Coordinator: NSObject, UISearchBarDelegate {
var parent: SearchBar
init(_ parent: SearchBar) {
self.parent = parent
}
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
parent.text = searchBar.text ?? ""
parent.onSearchButtonChanged()
}
}
}
struct MapView: UIViewRepresentable {
@Binding var landmarks: [Landmark]
func makeUIView(context: Context) -> MKMapView {
MKMapView(frame: .zero)
}
func updateUIView(_ uiView: MKMapView, context: Context) {
updateAnnotations(from: uiView)
}
private func updateAnnotations(from mapView: MKMapView) {
mapView.removeAnnotations(mapView.annotations)
let annotations = landmarks.map(LandmarkAnnotation.init)
mapView.addAnnotations(annotations)
if let firstLandmark = landmarks.first {
let span = MKCoordinateSpan(latitudeDelta: 0.05, longitudeDelta: 0.05)
let region = MKCoordinateRegion(center: firstLandmark.coordinate, span: span)
mapView.setRegion(region, animated: true)
}
}
}
class LandmarkAnnotation: NSObject, MKAnnotation {
let id: String
let name: String
var coordinate: CLLocationCoordinate2D
init(landmark: Landmark) {
self.id = landmark.id
self.name = landmark.name
self.coordinate = landmark.coordinate
}
var title: String? {
return name
}
}
感想
今回は、マップアプリに検索機能をつけるのをやってみました。まだまだ改良が必要ですが、参考になりそうなので、記録を残す目的で記事を書いてみました。
Discussion