Мы внедряем панель поиска в GoogleMaps, которая возвращает потенциальные местоположения. После выбора GoogleMaps обновляет выбранное местоположение. Чтобы реализовать эту функциональность, мы перерабатываем и повторно используем ключи API и проект из старой статьи: https://medium.com/@mtxsaalis/google-maps-and-google-places-with-swift-uikit-79a84c49707c. (См. шаги 1–3).

Вне класса ViewController мы импортируем
import GoogleMaps import GooglePlaces
В классе ViewController мы объявляем следующие переменные
var resultsViewController: GMSAutocompleteResultsViewController?
var searchController: UISearchController?
var resultView: UITextView?
var locationManager: CLLocationManager!
var currentLocation: CLLocation?
var mapView: GMSMapView!
var placesClient: GMSPlacesClient!
var preciseLocationZoomLevel: Float = 15.0
var approximateLocationZoomLevel: Float = 10.0
Наша панель поиска будет в верхней части экрана. Он имеет автозаполнение для мест GMS, UIsearchcontroller и текстовый интерфейс просмотра.
В приведенном выше фрагменте кода мы также устанавливаем менеджер местоположений и placeClient, которые возвращают места.
В классе ViewController в viewDidLoad()
Мы устанавливаем представления панели поиска и результатов следующим образом:
resultsViewController = GMSAutocompleteResultsViewController()
resultsViewController?.delegate = self
searchController = UISearchController(searchResultsController: resultsViewController)
searchController?.searchResultsUpdater = resultsViewController
let subView = UIView(frame: CGRect(x: 0, y: 65.0, width: 350.0, height: 45.0))
subView.addSubview((searchController?.searchBar)!)
//view.addSubview(subView)
searchController?.searchBar.sizeToFit()
searchController?.hidesNavigationBarDuringPresentation = false
// When UISearchController presents the results view, present it in
// this view controller, not one further up the chain.
definesPresentationContext = true
Настройка mapView аналогична предыдущей статье, за исключением того, что мы добавляем к ней подвид. Панель поиска является подвидом. Мы также исключаем распознаватель жестов. Теперь приложение увидит его при нажатии на строку поиска.
mapView.gestureRecognizers?.removeAll()
mapView.addSubview(subView)
view.addSubview(mapView)
Весь viewDidLoad() находится здесь:
override func viewDidLoad() {
super.viewDidLoad()
resultsViewController = GMSAutocompleteResultsViewController()
resultsViewController?.delegate = self
searchController = UISearchController(searchResultsController: resultsViewController)
searchController?.searchResultsUpdater = resultsViewController
let subView = UIView(frame: CGRect(x: 0, y: 65.0, width: 350.0, height: 45.0))
subView.addSubview((searchController?.searchBar)!)
//view.addSubview(subView)
searchController?.searchBar.sizeToFit()
searchController?.hidesNavigationBarDuringPresentation = false
// When UISearchController presents the results view, present it in
// this view controller, not one further up the chain.
definesPresentationContext = true
// Do any additional setup after loading the view.
// Create a GMSCameraPosition that tells the map to display the
// coordinate -33.86,151.20 at zoom level 6.
// Initialize the location manager.
locationManager = CLLocationManager()
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.requestWhenInUseAuthorization()
locationManager.distanceFilter = 50
locationManager.startUpdatingLocation()
locationManager.delegate = self
placesClient = GMSPlacesClient.shared()
// A default location to use when location permission is not granted.
let defaultLocation = CLLocation(latitude: -33.869405, longitude: 151.199)
// Create a map.
let zoomLevel = locationManager.accuracyAuthorization == .fullAccuracy ? preciseLocationZoomLevel : approximateLocationZoomLevel
let camera = GMSCameraPosition.camera(withLatitude: defaultLocation.coordinate.latitude,
longitude: defaultLocation.coordinate.longitude,
zoom: zoomLevel)
mapView = GMSMapView.map(withFrame: view.bounds, camera: camera)
mapView.settings.myLocationButton = true
mapView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
mapView.isMyLocationEnabled = true
mapView.gestureRecognizers?.removeAll()
mapView.addSubview(subView)
view.addSubview(mapView)
mapView.isHidden = true
}
}
У нас есть следующее расширение из документации платформы GoogleMaps для автозаполнения мест.
extension ViewController: GMSAutocompleteResultsViewControllerDelegate {
func resultsController(_ resultsController: GMSAutocompleteResultsViewController,
didAutocompleteWith place: GMSPlace) {
searchController?.isActive = false
// Do something with the selected place.
print("Place name: \(place.name)")
print("Place address: \(place.formattedAddress)")
print("Place attributions: \(place.attributions)")
}
func resultsController(_ resultsController: GMSAutocompleteResultsViewController,
didFailAutocompleteWithError error: Error){
// TODO: handle the error.
print("Error: ", error.localizedDescription)
}
// Turn the network activity indicator on and off again.
func didRequestAutocompletePredictions(forResultsController resultsController: GMSAutocompleteResultsViewController) {
UIApplication.shared.isNetworkActivityIndicatorVisible = true
}
func didUpdateAutocompletePredictions(forResultsController resultsController: GMSAutocompleteResultsViewController) {
UIApplication.shared.isNetworkActivityIndicatorVisible = false
}
}
Мы модифицируем его расширение func resultsController, вставив следующий фрагмент:
func updateLoc(finished: () -> Void) {
locationManager(CLLocationManager(), didUpdateLocations: [CLLocation(latitude: place.coordinate.latitude, longitude: place.coordinate.longitude)])
finished()
}
updateLoc{
mapView.translatesAutoresizingMaskIntoConstraints = true
print("EEEEEEEEENNNNNNDDDDDD")
}
Теперь расширение выглядит так:
extension ViewController: GMSAutocompleteResultsViewControllerDelegate {
func resultsController(_ resultsController: GMSAutocompleteResultsViewController,
didAutocompleteWith place: GMSPlace) {
searchController?.isActive = false
// Do something with the selected place.
print("Place name: \(place.name)")
print("Place address: \(place.formattedAddress)")
print("Place attributions: \(place.attributions)")
print("Place coord: \(place.placeID)")
func updateLoc(finished: () -> Void) {
locationManager(CLLocationManager(), didUpdateLocations: [CLLocation(latitude: place.coordinate.latitude, longitude: place.coordinate.longitude)])
finished()
}
updateLoc{
mapView.translatesAutoresizingMaskIntoConstraints = true
print("EEEEEEEEENNNNNNDDDDDD")
}
}
func resultsController(_ resultsController: GMSAutocompleteResultsViewController,
didFailAutocompleteWithError error: Error){
// TODO: handle the error.
print("Error: ", error.localizedDescription)
}
// Turn the network activity indicator on and off again.
func didRequestAutocompletePredictions(forResultsController resultsController: GMSAutocompleteResultsViewController) {
UIApplication.shared.isNetworkActivityIndicatorVisible = true
}
func didUpdateAutocompletePredictions(forResultsController resultsController: GMSAutocompleteResultsViewController) {
UIApplication.shared.isNetworkActivityIndicatorVisible = false
}
}
Обратите внимание, что у нас есть это расширение из предыдущего проекта:
// Delegates to handle events for the location manager.
extension ViewController: CLLocationManagerDelegate {
// Handle incoming location events.
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let location: CLLocation = locations.last!
print("Locationsssssssssssssss have chaaaaannnngggeeeddd: \(location)")
let zoomLevel = locationManager.accuracyAuthorization == .fullAccuracy ? preciseLocationZoomLevel : approximateLocationZoomLevel
let camera = GMSCameraPosition.camera(withLatitude: location.coordinate.latitude,
longitude: location.coordinate.longitude,
zoom: zoomLevel)
if mapView.isHidden {
mapView.isHidden = false
mapView.camera = camera
} else {
mapView.animate(to: camera)
}
}
// Populate the array with the list of likely places.
// Handle authorization for the location manager.
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
// Check accuracy authorization
let accuracy = manager.accuracyAuthorization
switch accuracy {
case .fullAccuracy:
print("Location accuracy is precise.")
case .reducedAccuracy:
print("Location accuracy is not precise.")
@unknown default:
fatalError()
}
// Handle authorization status
switch status {
case .restricted:
print("Location access was restricted.")
case .denied:
print("User denied access to location.")
// Display the map using the default location.
mapView.isHidden = false
case .notDetermined:
print("Location status not determined.")
case .authorizedAlways: fallthrough
case .authorizedWhenInUse:
print("Location status is OK.")
@unknown default:
fatalError()
}
}
// Handle location manager errors.
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
locationManager.stopUpdatingLocation()
print("Error here: \(error)")
}
}
Вот и все, полный файл ViewController приведен ниже:
//
// ViewController.swift
// GoogleMapSearchPlaces
//
// Created by CHRISTIAN BEYNIS on 2/22/23.
//
import UIKit
import GoogleMaps
import GooglePlaces
class ViewController: UIViewController{
var resultsViewController: GMSAutocompleteResultsViewController?
var searchController: UISearchController?
var resultView: UITextView?
var locationManager: CLLocationManager!
var currentLocation: CLLocation?
var mapView: GMSMapView!
var placesClient: GMSPlacesClient!
var preciseLocationZoomLevel: Float = 15.0
var approximateLocationZoomLevel: Float = 10.0
override func viewDidLoad() {
super.viewDidLoad()
resultsViewController = GMSAutocompleteResultsViewController()
resultsViewController?.delegate = self
searchController = UISearchController(searchResultsController: resultsViewController)
searchController?.searchResultsUpdater = resultsViewController
let subView = UIView(frame: CGRect(x: 0, y: 65.0, width: 350.0, height: 45.0))
subView.addSubview((searchController?.searchBar)!)
//view.addSubview(subView)
searchController?.searchBar.sizeToFit()
searchController?.hidesNavigationBarDuringPresentation = false
// When UISearchController presents the results view, present it in
// this view controller, not one further up the chain.
definesPresentationContext = true
// Do any additional setup after loading the view.
// Create a GMSCameraPosition that tells the map to display the
// coordinate -33.86,151.20 at zoom level 6.
// Initialize the location manager.
locationManager = CLLocationManager()
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.requestWhenInUseAuthorization()
locationManager.distanceFilter = 50
locationManager.startUpdatingLocation()
locationManager.delegate = self
placesClient = GMSPlacesClient.shared()
// A default location to use when location permission is not granted.
let defaultLocation = CLLocation(latitude: -33.869405, longitude: 151.199)
// Create a map.
let zoomLevel = locationManager.accuracyAuthorization == .fullAccuracy ? preciseLocationZoomLevel : approximateLocationZoomLevel
let camera = GMSCameraPosition.camera(withLatitude: defaultLocation.coordinate.latitude,
longitude: defaultLocation.coordinate.longitude,
zoom: zoomLevel)
mapView = GMSMapView.map(withFrame: view.bounds, camera: camera)
mapView.settings.myLocationButton = true
mapView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
mapView.isMyLocationEnabled = true
// Add the map to the view, hide it until we've got a location update.
mapView.gestureRecognizers?.removeAll()
//mapView.translatesAutoresizingMaskIntoConstraints = false
//mapView.topAnchor.constraint(equalTo: view.topAnchor, constant:100)
//mapView.heightAnchor.constraint(equalToConstant: 600).isActive = true
//mapView.widthAnchor.constraint(equalToConstant: 400).isActive = true
mapView.addSubview(subView)
//view.addSubview(subView)
//mapView.topAnchor.constraint(greaterThanOrEqualTo: view.bottomAnchor, constant: -40).isActive = true
view.addSubview(mapView)
mapView.isHidden = true
}
}
// Delegates to handle events for the location manager.
extension ViewController: CLLocationManagerDelegate {
// Handle incoming location events.
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let location: CLLocation = locations.last!
print("Locationsssssssssssssss have chaaaaannnngggeeeddd: \(location)")
let zoomLevel = locationManager.accuracyAuthorization == .fullAccuracy ? preciseLocationZoomLevel : approximateLocationZoomLevel
let camera = GMSCameraPosition.camera(withLatitude: location.coordinate.latitude,
longitude: location.coordinate.longitude,
zoom: zoomLevel)
if mapView.isHidden {
mapView.isHidden = false
mapView.camera = camera
} else {
mapView.animate(to: camera)
}
}
// Populate the array with the list of likely places.
// Handle authorization for the location manager.
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
// Check accuracy authorization
let accuracy = manager.accuracyAuthorization
switch accuracy {
case .fullAccuracy:
print("Location accuracy is precise.")
case .reducedAccuracy:
print("Location accuracy is not precise.")
@unknown default:
fatalError()
}
// Handle authorization status
switch status {
case .restricted:
print("Location access was restricted.")
case .denied:
print("User denied access to location.")
// Display the map using the default location.
mapView.isHidden = false
case .notDetermined:
print("Location status not determined.")
case .authorizedAlways: fallthrough
case .authorizedWhenInUse:
print("Location status is OK.")
@unknown default:
fatalError()
}
}
// Handle location manager errors.
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
locationManager.stopUpdatingLocation()
print("Error here: \(error)")
}
}
extension ViewController: GMSAutocompleteResultsViewControllerDelegate {
func resultsController(_ resultsController: GMSAutocompleteResultsViewController,
didAutocompleteWith place: GMSPlace) {
searchController?.isActive = false
// Do something with the selected place.
print("Place name: \(place.name)")
print("Place address: \(place.formattedAddress)")
print("Place attributions: \(place.attributions)")
print("Place coord: \(place.placeID)")
func updateLoc(finished: () -> Void) {
locationManager(CLLocationManager(), didUpdateLocations: [CLLocation(latitude: place.coordinate.latitude, longitude: place.coordinate.longitude)])
finished()
}
updateLoc{
mapView.translatesAutoresizingMaskIntoConstraints = true
print("EEEEEEEEENNNNNNDDDDDD")
}
}
func resultsController(_ resultsController: GMSAutocompleteResultsViewController,
didFailAutocompleteWithError error: Error){
// TODO: handle the error.
print("Error: ", error.localizedDescription)
}
// Turn the network activity indicator on and off again.
func didRequestAutocompletePredictions(forResultsController resultsController: GMSAutocompleteResultsViewController) {
UIApplication.shared.isNetworkActivityIndicatorVisible = true
}
func didUpdateAutocompletePredictions(forResultsController resultsController: GMSAutocompleteResultsViewController) {
UIApplication.shared.isNetworkActivityIndicatorVisible = false
}
}

идентификатор на гитхабе: Chrisb5a
если вы заинтересованы в открытии своего бизнеса или изучении новых навыков, не стесняйтесь обращаться к нам.