RxSwiftを使ってMapKitで現在地から場所をサジェストするauto completeを実装するサンプル
現在地付近のの施設を検索できるサンプルになります
MapKitを使用して現在地を取得しながら、UISearchBarに入力した結果をtableViewに返すサンプルになります。
実際に使用する際は、現在地の取得の許可を得るために
info.plistに
Privacy - Location When In Use Usage Description
Privacy - Location Always and When In Use Usage Description
をかいてください。
現在地の取得が、
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation])
常にアップデートされるため、
**メートル以内の変更は通知しないよう以下の関数を定義してあります。
func distinctUntilChangeGreaterThan(meters: CLLocationDistance) -> Observable<CLLocation>
渡ってきたCLLocationを
.distinctUntilChangeGreaterThan(meters: CLLocationDistance(1000))
1000メートル以内の変化は通知しないように。
var myLocationRelay = BehaviorRelay<CLLocation?>(value: nil)
myLocationRelay
.compactMap { $0 }
.distinctUntilChangeGreaterThan(meters: CLLocationDistance(1000))
.subscribe(onNext: { [weak self] coordinate in
let span = MKCoordinateSpan(latitudeDelta: 0.001, longitudeDelta: 0.001)
let region = MKCoordinateRegion(center: coordinate.coordinate, span: span)
self?.searchCompleter.region = region
})
.disposed(by: bag)
すべてのコード
import CoreLocation
import MapKit
import RxCocoa
import RxSwift
import UIKit
class FindLocationViewController: UIViewController {
var viewModel: FindLocationViewModel!
var bag = DisposeBag()
var searchCompleter = MKLocalSearchCompleter()
var locationManager: CLLocationManager?
var searchResults = [MKLocalSearchCompletion]()
var myLocationRelay = BehaviorRelay<CLLocation?>(value: nil)
@IBOutlet private weak var searchResultsTable: UITableView!
@IBOutlet weak var searchBar: UISearchBar!
override func viewDidLoad() {
super.viewDidLoad()
initialSettings()
viewModel.setUp()
setBind()
whereIsMyLocation()
}
private func initialSettings() {
searchBar.delegate = self
searchResultsTable.delegate = self
searchResultsTable.dataSource = self
searchCompleter.delegate = self
let categories: [MKPointOfInterestCategory] = [.fitnessCenter]
let filters = MKPointOfInterestFilter(including: categories)
searchCompleter.pointOfInterestFilter = .some(filters)
}
private func setBind() {
myLocationRelay
.compactMap { $0 }
.distinctUntilChangeGreaterThan(meters: CLLocationDistance(1000))
.subscribe(onNext: { [weak self] coordinate in
let span = MKCoordinateSpan(latitudeDelta: 0.001, longitudeDelta: 0.001)
let region = MKCoordinateRegion(center: coordinate.coordinate, span: span)
self?.searchCompleter.region = region
})
.disposed(by: bag)
}
private func whereIsMyLocation() {
locationManager = CLLocationManager()
locationManager?.delegate = self
locationManager?.requestWhenInUseAuthorization()
if CLLocationManager.locationServicesEnabled() {
locationManager!.startUpdatingLocation()
}
}
}
extension FindLocationViewController: CLLocationManagerDelegate {
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
guard let newLocation = locations.last else {
return
}
let location: CLLocationCoordinate2D
= CLLocationCoordinate2DMake(newLocation.coordinate.latitude, newLocation.coordinate.longitude)
let formatter = DateFormatter()
formatter.timeZone = TimeZone(identifier: "Asia/Tokyo")
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss'Z'"
let date = formatter.string(from: newLocation.timestamp)
print("緯度:", location.latitude, "経度:", location.longitude, "時間:", date)
let ccLoctaion = CLLocation(latitude: location.latitude, longitude: location.longitude)
myLocationRelay.accept(ccLoctaion)
}
}
extension FindLocationViewController: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
let result = searchResults[indexPath.row]
let searchRequest = MKLocalSearch.Request(completion: result)
let search = MKLocalSearch(request: searchRequest)
search.start { response, _ in
guard let coordinate = response?.mapItems[0].placemark.coordinate else {
return
}
guard let name = response?.mapItems[0].name else {
return
}
let lat = coordinate.latitude
let lon = coordinate.longitude
print(lat)
print(lon)
print(name)
let preVC = self.presentingViewController as! WhichGymViewController
let gymInfo = GymInfo(coodinate: coordinate, name: name)
preVC.viewModel.selectedGymRelay.accept(gymInfo)
self.dismiss(animated: true, completion: nil)
}
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return searchResults.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let searchResult = searchResults[indexPath.row]
let cell = UITableViewCell(style: .subtitle, reuseIdentifier: nil)
cell.textLabel?.text = searchResult.title
cell.detailTextLabel?.text = searchResult.subtitle
return cell
}
}
extension FindLocationViewController: MKLocalSearchCompleterDelegate & UISearchBarDelegate {
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
searchCompleter.queryFragment = searchText
}
func completerDidUpdateResults(_ completer: MKLocalSearchCompleter) {
searchResults = completer.results
searchResultsTable.reloadData()
}
func completer(_ completer: MKLocalSearchCompleter, didFailWithError error: Error) {
// Error
}
func searchBarShouldBeginEditing(_ searchBar: UISearchBar) -> Bool {
return true
}
}
import CoreLocation
import Foundation
import RxSwift
extension CLLocationCoordinate2D: Equatable {}
public func == (lhs: CLLocationCoordinate2D, rhs: CLLocationCoordinate2D) -> Bool {
return lhs.latitude == rhs.latitude && lhs.longitude == rhs.longitude
}
extension ObservableType where Element == CLLocation {
func distinctUntilChangeGreaterThan(meters: CLLocationDistance) -> Observable<CLLocation> {
return scan(CLLocation(), accumulator: { lastLocation, location in
if lastLocation.distance(from: location) > meters {
return location
} else {
return lastLocation
}
}).distinctUntilChanged { lhs, rhs in
lhs.coordinate == rhs.coordinate
}
}
}
Author And Source
この問題について(RxSwiftを使ってMapKitで現在地から場所をサジェストするauto completeを実装するサンプル), 我々は、より多くの情報をここで見つけました https://qiita.com/YOSUKE8080/items/d6c23d7c3053134b5d6f著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .