我目前正在尝试实现与搜索功能关联的地图。对于包含表格视图的叠加层,我决定选择一个名为FloatingPanel的库。无论如何,这并不重要,因为它不会影响搜索栏等的代码。
要搜索匹配的结果,我每次在搜索栏中更改文本时都会执行MKLocalSearch.Request
。它可以工作,但是匹配结果有点奇怪-大多数情况下,该函数只返回一个匹配项,即使应该更多。此外,某些时候,有些村庄没有比赛,但体育馆却没有。
我要的是在用户开始输入内容后立即显示一些建议。例如,如果他开始输入“ Los”,我希望该功能已经返回一个建议:“ Los Angeles”等等,就像在实际的Apple Map应用程序中一样。
import UIKit
import MapKit
import FloatingPanel
class MapViewController: UIViewController, FloatingPanelControllerDelegate, UISearchBarDelegate {
@IBOutlet weak var mapView: MKMapView!
let locationManager = CLLocationManager()
var fpc: FloatingPanelController!
var searchVC: BottomSheetViewController!
var resultSearchController:UISearchController? = nil
override func viewDidLoad() {
super.viewDidLoad()
let sb = UIStoryboard(name: "Main", bundle: nil)
let vc = sb.instantiateViewController(withIdentifier: "SearchPanel") as! BottomSheetViewController
vc.mapView = mapView
fpc = FloatingPanelController()
fpc.delegate = self
fpc.surfaceView.backgroundColor = .clear
fpc.surfaceView.cornerRadius = 9.0
fpc.surfaceView.shadowHidden = false
searchVC = storyboard?.instantiateViewController(withIdentifier: "SearchPanel") as? BottomSheetViewController
fpc.set(contentViewController: searchVC)
fpc.track(scrollView: searchVC.tableView)
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.requestWhenInUseAuthorization()
locationManager.requestLocation()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
fpc.addPanel(toParent: self, animated: true)
searchVC.searchBar.delegate = self
}
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
guard let mapView = mapView,
let searchBarText = searchVC.searchBar.text else { return }
let request = MKLocalSearch.Request()
request.naturalLanguageQuery = searchBarText
request.region = mapView.region
let search = MKLocalSearch(request: request)
search.start { response, _ in
guard let response = response else {
return
}
self.searchVC.matchingItems = response.mapItems
self.searchVC.tableView.reloadData()
}
}
func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
searchBar.resignFirstResponder()
searchBar.showsCancelButton = false
searchVC.hideHeader()
fpc.move(to: .half, animated: true)
}
func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) {
searchBar.showsCancelButton = true
searchVC.showHeader()
searchVC.tableView.alpha = 1.0
fpc.move(to: .full, animated: true)
}
func floatingPanelDidMove(_ vc: FloatingPanelController) {
let y = vc.surfaceView.frame.origin.y
let tipY = vc.originYOfSurface(for: .tip)
if y > tipY - 44.0 {
let progress = max(0.0, min((tipY - y) / 44.0, 1.0))
self.searchVC.tableView.alpha = progress
}
}
func floatingPanelWillBeginDragging(_ vc: FloatingPanelController) {
if vc.position == .full {
searchVC.searchBar.showsCancelButton = false
searchVC.searchBar.resignFirstResponder()
}
}
func floatingPanelDidEndDragging(_ vc: FloatingPanelController, withVelocity velocity: CGPoint, targetPosition: FloatingPanelPosition) {
if targetPosition != .full {
searchVC.hideHeader()
}
UIView.animate(withDuration: 0.25,
delay: 0.0,
options: .allowUserInteraction,
animations: {
if targetPosition == .tip {
self.searchVC.tableView.alpha = 0.0
} else {
self.searchVC.tableView.alpha = 1.0
}
}, completion: nil)
}
}
数据正在另一个视图控制器内部的表视图中显示:
class BottomSheetViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, UISearchBarDelegate {
@IBOutlet weak var tableView: UITableView!
@IBOutlet weak var searchBar: UISearchBar!
@IBOutlet weak var visualEffectView: UIVisualEffectView!
var matchingItems: [MKMapItem] = []
var mapView: MKMapView? = nil
override func viewDidLoad() {
super.viewDidLoad()
tableView.dataSource = self
tableView.delegate = self
searchBar.placeholder = "Search for a place or address"
let textField = searchBar.value(forKey: "_searchField") as! UITextField
textField.font = UIFont(name: textField.font!.fontName, size: 15.0)
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
if #available(iOS 10, *) {
visualEffectView.layer.cornerRadius = 9.0
visualEffectView.clipsToBounds = true
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return matchingItems.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell") as! SearchCell
let selectedItem = matchingItems[indexPath.row].placemark
cell.titleLabel.text = selectedItem.name
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: false)
}
}
SearchCell:
class SearchCell: UITableViewCell {
@IBOutlet weak var titleLabel: UILabel!
}