Auf einer Karte den aktuellen Ort auswählen und Details einblenden
In dieser Anleitung wird gezeigt, wie Sie eine iOS-App erstellen, die den aktuellen Standort des Geräts abruft, wahrscheinliche Standorte ermittelt, den Nutzer auffordert, den besten Treffer auszuwählen, und eine Kartenmarkierung für den ausgewählten Standort anzeigt.
Es ist für Nutzer geeignet, die eine Vorkenntnisse in Swift oder Objective-C haben und sich mit Xcode auskennen. Einen Leitfaden zum Erstellen von Karten für fortgeschrittene Nutzer finden Sie im Entwicklerhandbuch.
In dieser Anleitung erstellen Sie die folgende Karte. Die Kartenmarkierung befindet sich in San Francisco, Kalifornien, wird jedoch dorthin verschoben, wo sich das Gerät oder der Simulator befindet.
In dieser Anleitung werden das Places SDK for iOS, das Maps SDK for iOS und das Apple Core Location Framework verwendet.
Code abrufen
Klonen Sie das Google Maps iOS-Beispiel-Repository oder laden Sie es von GitHub herunter.Klicken Sie alternativ auf die folgende Schaltfläche, um den Quellcode herunterzuladen:
Swift MapViewController
/* * Copyright 2016 Google Inc. All rights reserved. * * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this * file except in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF * ANY KIND, either express or implied. See the License for the specific language governing * permissions and limitations under the License. */ import UIKit import GoogleMaps import GooglePlaces class MapViewController: UIViewController { var locationManager: CLLocationManager! var currentLocation: CLLocation? var mapView: GMSMapView! var placesClient: GMSPlacesClient! var preciseLocationZoomLevel: Float = 15.0 var approximateLocationZoomLevel: Float = 10.0 // An array to hold the list of likely places. var likelyPlaces: [GMSPlace] = [] // The currently selected place. var selectedPlace: GMSPlace? // Update the map once the user has made their selection. @IBAction func unwindToMain(segue: UIStoryboardSegue) { // Clear the map. mapView.clear() // Add a marker to the map. if let place = selectedPlace { let marker = GMSMarker(position: place.coordinate) marker.title = selectedPlace?.name marker.snippet = selectedPlace?.formattedAddress marker.map = mapView } listLikelyPlaces() } override func viewDidLoad() { super.viewDidLoad() // 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. view.addSubview(mapView) mapView.isHidden = true listLikelyPlaces() } // Populate the array with the list of likely places. func listLikelyPlaces() { // Clean up from previous sessions. likelyPlaces.removeAll() let placeFields: GMSPlaceField = [.name, .coordinate] placesClient.findPlaceLikelihoodsFromCurrentLocation(withPlaceFields: placeFields) { (placeLikelihoods, error) in guard error == nil else { // TODO: Handle the error. print("Current Place error: \(error!.localizedDescription)") return } guard let placeLikelihoods = placeLikelihoods else { print("No places found.") return } // Get likely places and add to the list. for likelihood in placeLikelihoods { let place = likelihood.place self.likelyPlaces.append(place) } } } // Prepare the segue. override func prepare(for segue: UIStoryboardSegue, sender: Any?) { if segue.identifier == "segueToSelect" { if let nextViewController = segue.destination as? PlacesViewController { nextViewController.likelyPlaces = likelyPlaces } } } } // Delegates to handle events for the location manager. extension MapViewController: CLLocationManagerDelegate { // Handle incoming location events. func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) { let location: CLLocation = locations.last! print("Location: \(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) } listLikelyPlaces() } // 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: \(error)") } }
Swift PlacesViewController
/* * Copyright 2017 Google Inc. All rights reserved. * * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this * file except in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF * ANY KIND, either express or implied. See the License for the specific language governing * permissions and limitations under the License. */ import UIKit import GooglePlaces class PlacesViewController: UIViewController { @IBOutlet weak var tableView: UITableView! // An array to hold the list of possible locations. var likelyPlaces: [GMSPlace] = [] var selectedPlace: GMSPlace? // Cell reuse id (cells that scroll out of view can be reused). let cellReuseIdentifier = "cell" override func viewDidLoad() { super.viewDidLoad() // Register the table view cell class and its reuse id. tableView.register(UITableViewCell.self, forCellReuseIdentifier: cellReuseIdentifier) // This view controller provides delegate methods and row data for the table view. tableView.delegate = self tableView.dataSource = self tableView.reloadData() } // Pass the selected place to the new view controller. override func prepare(for segue: UIStoryboardSegue, sender: Any?) { if segue.identifier == "unwindToMain" { if let nextViewController = segue.destination as? MapViewController { nextViewController.selectedPlace = selectedPlace } } } } // Respond when a user selects a place. extension PlacesViewController: UITableViewDelegate { func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { selectedPlace = likelyPlaces[indexPath.row] performSegue(withIdentifier: "unwindToMain", sender: self) } // Adjust cell height to only show the first five items in the table // (scrolling is disabled in IB). func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { return self.tableView.frame.size.height/5 } // Make table rows display at proper height if there are less than 5 items. func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat { if (section == tableView.numberOfSections - 1) { return 1 } return 0 } } // Populate the table with the list of most likely places. extension PlacesViewController: UITableViewDataSource { func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return likelyPlaces.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: cellReuseIdentifier, for: indexPath) let collectionItem = likelyPlaces[indexPath.row] cell.textLabel?.text = collectionItem.name return cell } }
Obj-C MapViewController
// // MapsViewController.m // current-place-on-map // // Created by Chris Arriola on 9/18/20. // Copyright © 2020 William French. All rights reserved. // #import "MapViewController.h" #import "PlacesViewController.h" @import CoreLocation; @import GooglePlaces; @import GoogleMaps; @interface MapViewController () <CLLocationManagerDelegate> @end @implementation MapViewController { CLLocationManager *locationManager; CLLocation * _Nullable currentLocation; GMSMapView *mapView; GMSPlacesClient *placesClient; float preciseLocationZoomLevel; float approximateLocationZoomLevel; // An array to hold the list of likely places. NSMutableArray<GMSPlace *> *likelyPlaces; // The currently selected place. GMSPlace * _Nullable selectedPlace; } - (void)viewDidLoad { [super viewDidLoad]; preciseLocationZoomLevel = 15.0; approximateLocationZoomLevel = 15.0; // Initialize the location manager. locationManager = [[CLLocationManager alloc] init]; locationManager.desiredAccuracy = kCLLocationAccuracyBest; [locationManager requestWhenInUseAuthorization]; locationManager.distanceFilter = 50; [locationManager startUpdatingLocation]; locationManager.delegate = self; placesClient = [GMSPlacesClient sharedClient]; // A default location to use when location permission is not granted. CLLocationCoordinate2D defaultLocation = CLLocationCoordinate2DMake(-33.869405, 151.199); // Create a map. float zoomLevel = locationManager.accuracyAuthorization == CLAccuracyAuthorizationFullAccuracy ? preciseLocationZoomLevel : approximateLocationZoomLevel; GMSCameraPosition *camera = [GMSCameraPosition cameraWithLatitude:defaultLocation.latitude longitude:defaultLocation.longitude zoom:zoomLevel]; mapView = [GMSMapView mapWithFrame:self.view.bounds camera:camera]; mapView.settings.myLocationButton = YES; mapView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; mapView.myLocationEnabled = YES; // Add the map to the view, hide it until we've got a location update. [self.view addSubview:mapView]; mapView.hidden = YES; [self listLikelyPlaces]; } // Populate the array with the list of likely places. - (void) listLikelyPlaces { // Clean up from previous sessions. likelyPlaces = [NSMutableArray array]; GMSPlaceField placeFields = GMSPlaceFieldName | GMSPlaceFieldCoordinate; [placesClient findPlaceLikelihoodsFromCurrentLocationWithPlaceFields:placeFields callback:^(NSArray<GMSPlaceLikelihood *> * _Nullable likelihoods, NSError * _Nullable error) { if (error != nil) { // TODO: Handle the error. NSLog(@"Current Place error: %@", error.localizedDescription); return; } if (likelihoods == nil) { NSLog(@"No places found."); return; } for (GMSPlaceLikelihood *likelihood in likelihoods) { GMSPlace *place = likelihood.place; [likelyPlaces addObject:place]; } }]; } // Update the map once the user has made their selection. - (void) unwindToMain:(UIStoryboardSegue *)segue { // Clear the map. [mapView clear]; // Add a marker to the map. if (selectedPlace != nil) { GMSMarker *marker = [GMSMarker markerWithPosition:selectedPlace.coordinate]; marker.title = selectedPlace.name; marker.snippet = selectedPlace.formattedAddress; marker.map = mapView; } [self listLikelyPlaces]; } // Prepare the segue. - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { if ([segue.identifier isEqualToString:@"segueToSelect"]) { if ([segue.destinationViewController isKindOfClass:[PlacesViewController class]]) { PlacesViewController *placesViewController = (PlacesViewController *)segue.destinationViewController; placesViewController.likelyPlaces = likelyPlaces; } } } // Delegates to handle events for the location manager. #pragma mark - CLLocationManagerDelegate // Handle incoming location events. - (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations { CLLocation *location = locations.lastObject; NSLog(@"Location: %@", location); float zoomLevel = locationManager.accuracyAuthorization == CLAccuracyAuthorizationFullAccuracy ? preciseLocationZoomLevel : approximateLocationZoomLevel; GMSCameraPosition * camera = [GMSCameraPosition cameraWithLatitude:location.coordinate.latitude longitude:location.coordinate.longitude zoom:zoomLevel]; if (mapView.isHidden) { mapView.hidden = NO; mapView.camera = camera; } else { [mapView animateToCameraPosition:camera]; } [self listLikelyPlaces]; } // Handle authorization for the location manager. - (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status { // Check accuracy authorization CLAccuracyAuthorization accuracy = manager.accuracyAuthorization; switch (accuracy) { case CLAccuracyAuthorizationFullAccuracy: NSLog(@"Location accuracy is precise."); break; case CLAccuracyAuthorizationReducedAccuracy: NSLog(@"Location accuracy is not precise."); break; } // Handle authorization status switch (status) { case kCLAuthorizationStatusRestricted: NSLog(@"Location access was restricted."); break; case kCLAuthorizationStatusDenied: NSLog(@"User denied access to location."); // Display the map using the default location. mapView.hidden = NO; case kCLAuthorizationStatusNotDetermined: NSLog(@"Location status not determined."); case kCLAuthorizationStatusAuthorizedAlways: case kCLAuthorizationStatusAuthorizedWhenInUse: NSLog(@"Location status is OK."); } } // Handle location manager errors. - (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error { [manager stopUpdatingLocation]; NSLog(@"Error: %@", error.localizedDescription); } @end
Obj-C PlacesViewController
// Copyright 2020 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #import "PlacesViewController.h" @interface PlacesViewController () <UITableViewDataSource, UITableViewDelegate> @property (nonatomic, weak) UITableView *tableView; @end @implementation PlacesViewController { // Cell reuse id (cells that scroll out of view can be reused). NSString *cellReuseIdentifier; } - (void)viewDidLoad { [super viewDidLoad]; cellReuseIdentifier = @"cell"; } -(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { } #pragma mark - UITableViewDelegate // Respond when a user selects a place. -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { self.selectedPlace = [self.likelyPlaces objectAtIndex:indexPath.row]; [self performSegueWithIdentifier:@"unwindToMain" sender:self]; } // Adjust cell height to only show the first five items in the table // (scrolling is disabled in IB). -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { return self.tableView.frame.size.height/5; } // Make table rows display at proper height if there are less than 5 items. -(CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section { if (section == tableView.numberOfSections - 1) { return 1; } return 0; } #pragma mark - UITableViewDataSource - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return self.likelyPlaces.count; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { return [tableView dequeueReusableCellWithIdentifier:cellReuseIdentifier forIndexPath:indexPath]; } @end
Erste Schritte
Swift-Paketmanager
Das Maps SDK for iOS kann mit dem Swift-Paketmanager installiert werden.
- Prüfen Sie, ob alle vorhandenen Abhängigkeiten des Maps SDK for iOS entfernt wurden.
- Öffnen Sie ein Terminalfenster und wechseln Sie zum Verzeichnis
tutorials/current-place-on-map
. -
Achten Sie darauf, dass der Xcode-Arbeitsbereich geschlossen ist, und führen Sie die folgenden Befehle aus:
sudo gem install cocoapods-deintegrate cocoapods-clean pod deintegrate pod cache clean --all rm Podfile rm current-place-on-map.xcworkspace
- Öffnen Sie Ihr Xcode-Projekt und löschen Sie die Podfile-Datei.
- Fügen Sie das Places SDK und das Maps SDK hinzu:
- Wählen Sie Datei > Paketabhängigkeiten hinzufügen aus.
- Geben Sie https://github.com/googlemaps/ios-places-sdk als URL ein, drücken Sie die Eingabetaste, um das Paket abzurufen, und klicken Sie auf Paket hinzufügen.
- Geben Sie https://github.com/googlemaps/ios-maps-sdk als URL ein, drücken Sie die Eingabetaste, um das Paket abzurufen, und klicken Sie auf Paket hinzufügen.
- Möglicherweise müssen Sie den Paketcache über Datei > Pakete > Paket-Cache zurücksetzen zurücksetzen.
Mit CocoaPods
- Laden Sie Xcode Version 15.0 oder höher herunter und installieren Sie es.
- Wenn Sie CocoaPods noch nicht haben, installieren Sie es unter macOS. Führen Sie dazu den folgenden Befehl über das Terminal aus:
sudo gem install cocoapods
- Rufen Sie das Verzeichnis
tutorials/current-place-on-map
auf. - Führe den Befehl
pod install
aus. Dadurch werden die inPodfile
angegebenen Maps und Places SDKs zusammen mit allen Abhängigkeiten installiert. - Führen Sie
pod outdated
aus, um die installierte Pod-Version mit neuen Updates zu vergleichen. Wenn eine neue Version erkannt wird, führen Siepod update
aus, umPodfile
zu aktualisieren und das neueste SDK zu installieren. Weitere Informationen finden Sie im CocoaPods-Leitfaden. - Öffnen Sie die Datei current-place-on-map.xcworkspace des Projekts (doppelklicken), um sie in Xcode zu öffnen. Sie müssen die Datei
.xcworkspace
verwenden, um das Projekt zu öffnen.
API-Schlüssel abrufen und die erforderlichen APIs aktivieren
Als letzten Schritt benötigen Sie noch einen Google API-Schlüssel, der zum Maps SDK for iOS und zur Places API berechtigt ist.
- Folgen Sie der Anleitung unter Erste Schritte mit der Google Maps Platform, um ein Rechnungskonto und ein Projekt einzurichten, das für diese beiden Produkte aktiviert ist.
- Folgen Sie der Anleitung unter API-Schlüssel anfordern, um einen API-Schlüssel für das zuvor eingerichtete Entwicklungsprojekt zu erstellen.
API-Schlüssel zur App hinzufügen
Füge deinen API-Schlüssel folgendermaßen in AppDelegate.swift
ein:
- Die folgende Importanweisung wurde der Datei hinzugefügt:
import GooglePlaces import GoogleMaps
- Bearbeiten Sie die folgende Zeile in der Methode
application(_:didFinishLaunchingWithOptions:)
und ersetzen Sie YOUR_API_KEY durch Ihren API-Schlüssel:GMSPlacesClient.provideAPIKey("YOUR_API_KEY") GMSServices.provideAPIKey("YOUR_API_KEY")
App erstellen und ausführen
- Verbinden Sie ein iOS-Gerät mit Ihrem Computer oder wählen Sie aus dem Pop-up-Menü für das Xcode-Schema einen Simulator aus.
- Wenn Sie ein Gerät verwenden, achten Sie darauf, dass die Standortdienste aktiviert sind. Wenn Sie einen Simulator verwenden, wählen Sie im Menü Features einen Standort aus.
- Klicken Sie in Xcode auf die Menüoption Product/Run (Produkt/Ausführen) oder das Symbol für die Wiedergabeschaltfläche.
- Xcode erstellt die App und führt sie dann auf dem Gerät oder im Simulator aus.
- Nun sollte eine Karte mit einer Reihe von Markierungen zu sehen sein, die um Ihren aktuellen Standort herum angeordnet sind.
Fehlerbehebung:
- Wenn Sie keine Karte sehen, prüfen Sie, ob Sie einen API-Schlüssel erhalten und ihn wie oben beschrieben in die App eingefügt haben. Prüfen Sie die Debugging-Konsole von Xcode auf Fehlermeldungen zum API-Schlüssel.
- Wenn du den API-Schlüssel durch den iOS-Paket-Identifikator eingeschränkt hast, füge den Paket-Identifikator für die App hinzu:
com.google.examples.current-place-on-map
. - Die Karte wird nicht richtig angezeigt, wenn die Berechtigungsanfrage für Standortdienste abgelehnt wird.
- Wenn du ein Gerät verwendest, rufe Einstellungen/Allgemein/Datenschutz/Standortdienste auf und aktiviere die Standortdienste wieder.
- Wenn Sie einen Simulator verwenden, rufen Sie Simulator/Reset Content and Settings... (Simulator/Inhalte und Einstellungen zurücksetzen...) auf.
- Sie benötigen eine gute WLAN- oder GPS-Verbindung.
- Wenn die App gestartet, aber keine Karte angezeigt wird, prüfen Sie, ob Sie die Info.plist-Datei für Ihr Projekt mit den entsprechenden Berechtigungen zur Standortermittlung aktualisiert haben. Weitere Informationen zum Umgang mit Berechtigungen finden Sie unten in der Anleitung zum Anfordern der Berechtigung zur Standortermittlung in der App.
- Verwenden Sie die Xcode-Debugging-Tools, um Logs aufzurufen und Fehler in der Anwendung zu beheben.
Code verstehen
In diesem Teil der Anleitung werden die wesentlichsten Teile der App current-place-on-map erläutert, damit Sie besser verstehen, wie Sie eine ähnliche App erstellen.
Die App current-place-on-map verfügt über zwei Ansichts-Controller. Mit einem Controller wird eine Karte mit dem aktuell vom Nutzer ausgewählten Ort angezeigt und mit dem anderen wird dem Nutzer eine Liste wahrscheinlicher Orte präsentiert, aus denen er auswählen kann. Jeder Ansichts-Controller hat dieselben Variablen für das Tracking der Liste wahrscheinlicher Orte (likelyPlaces
) und zum Anzeigen der Auswahl des Nutzers (selectedPlace
). Die Navigation zwischen Ansichten erfolgt mithilfe von Übergängen.
Berechtigung zur Standortermittlung wird angefordert
Ihre App muss den Nutzer um seine Einwilligung zur Verwendung der Standortdienste bitten. Füge dazu den Schlüssel NSLocationAlwaysUsageDescription
in die Datei Info.plist
für die App ein und setze den Wert jedes Schlüssels auf einen String, der beschreibt, wie die App Standortdaten verwenden möchte.
Standortmanager einrichten
Verwenden Sie CLLocationManager, um den aktuellen Standort des Geräts zu ermitteln und regelmäßige Updates anzufordern, wenn das Gerät an einen neuen Standort verlegt wird. In dieser Anleitung finden Sie den Code, den Sie benötigen, um den Gerätestandort abzurufen. Weitere Informationen findest du in der Anleitung zum Abrufen des Nutzerstandorts in der Apple Developer-Dokumentation.
- Deklarieren Sie den Standortmanager, den aktuellen Standort, die Kartenansicht, den Places-Client und die Standardzoomstufe auf Klassenebene.
- Initialisieren Sie den Standortmanager und
GMSPlacesClient
inviewDidLoad()
. - Deklarieren Sie Variablen, die die Liste möglicher Orte und den vom Nutzer ausgewählten Ort enthalten.
- Fügen Sie mithilfe einer Erweiterungsklausel Bevollmächtigte hinzu, um Ereignisse für den Standortmanager zu verarbeiten.
Swift
var locationManager: CLLocationManager! var currentLocation: CLLocation? var mapView: GMSMapView! var placesClient: GMSPlacesClient! var preciseLocationZoomLevel: Float = 15.0 var approximateLocationZoomLevel: Float = 10.0
Objective-C
CLLocationManager *locationManager; CLLocation * _Nullable currentLocation; GMSMapView *mapView; GMSPlacesClient *placesClient; float preciseLocationZoomLevel; float approximateLocationZoomLevel;
Swift
// Initialize the location manager. locationManager = CLLocationManager() locationManager.desiredAccuracy = kCLLocationAccuracyBest locationManager.requestWhenInUseAuthorization() locationManager.distanceFilter = 50 locationManager.startUpdatingLocation() locationManager.delegate = self placesClient = GMSPlacesClient.shared()
Objective-C
// Initialize the location manager. locationManager = [[CLLocationManager alloc] init]; locationManager.desiredAccuracy = kCLLocationAccuracyBest; [locationManager requestWhenInUseAuthorization]; locationManager.distanceFilter = 50; [locationManager startUpdatingLocation]; locationManager.delegate = self; placesClient = [GMSPlacesClient sharedClient];
Swift
// An array to hold the list of likely places. var likelyPlaces: [GMSPlace] = [] // The currently selected place. var selectedPlace: GMSPlace?
Objective-C
// An array to hold the list of likely places. NSMutableArray<GMSPlace *> *likelyPlaces; // The currently selected place. GMSPlace * _Nullable selectedPlace;
Swift
// Delegates to handle events for the location manager. extension MapViewController: CLLocationManagerDelegate { // Handle incoming location events. func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) { let location: CLLocation = locations.last! print("Location: \(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) } listLikelyPlaces() } // 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: \(error)") } }
Objective-C
// Delegates to handle events for the location manager. #pragma mark - CLLocationManagerDelegate // Handle incoming location events. - (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations { CLLocation *location = locations.lastObject; NSLog(@"Location: %@", location); float zoomLevel = locationManager.accuracyAuthorization == CLAccuracyAuthorizationFullAccuracy ? preciseLocationZoomLevel : approximateLocationZoomLevel; GMSCameraPosition * camera = [GMSCameraPosition cameraWithLatitude:location.coordinate.latitude longitude:location.coordinate.longitude zoom:zoomLevel]; if (mapView.isHidden) { mapView.hidden = NO; mapView.camera = camera; } else { [mapView animateToCameraPosition:camera]; } [self listLikelyPlaces]; } // Handle authorization for the location manager. - (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status { // Check accuracy authorization CLAccuracyAuthorization accuracy = manager.accuracyAuthorization; switch (accuracy) { case CLAccuracyAuthorizationFullAccuracy: NSLog(@"Location accuracy is precise."); break; case CLAccuracyAuthorizationReducedAccuracy: NSLog(@"Location accuracy is not precise."); break; } // Handle authorization status switch (status) { case kCLAuthorizationStatusRestricted: NSLog(@"Location access was restricted."); break; case kCLAuthorizationStatusDenied: NSLog(@"User denied access to location."); // Display the map using the default location. mapView.hidden = NO; case kCLAuthorizationStatusNotDetermined: NSLog(@"Location status not determined."); case kCLAuthorizationStatusAuthorizedAlways: case kCLAuthorizationStatusAuthorizedWhenInUse: NSLog(@"Location status is OK."); } } // Handle location manager errors. - (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error { [manager stopUpdatingLocation]; NSLog(@"Error: %@", error.localizedDescription); }
Karte hinzufügen
Erstellen Sie eine Karte und fügen Sie sie der Ansicht in viewDidLoad()
im Hauptansicht-Controller hinzu. Die Karte bleibt ausgeblendet, bis ein Standortupdate empfangen wird. Standortaktualisierungen werden über die Erweiterung CLLocationManagerDelegate
verarbeitet.
Swift
// 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. view.addSubview(mapView) mapView.isHidden = true
Objective-C
// A default location to use when location permission is not granted. CLLocationCoordinate2D defaultLocation = CLLocationCoordinate2DMake(-33.869405, 151.199); // Create a map. float zoomLevel = locationManager.accuracyAuthorization == CLAccuracyAuthorizationFullAccuracy ? preciseLocationZoomLevel : approximateLocationZoomLevel; GMSCameraPosition *camera = [GMSCameraPosition cameraWithLatitude:defaultLocation.latitude longitude:defaultLocation.longitude zoom:zoomLevel]; mapView = [GMSMapView mapWithFrame:self.view.bounds camera:camera]; mapView.settings.myLocationButton = YES; mapView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; mapView.myLocationEnabled = YES; // Add the map to the view, hide it until we've got a location update. [self.view addSubview:mapView]; mapView.hidden = YES;
Aufforderung des Nutzers, seinen aktuellen Ort auszuwählen
Verwenden Sie das Places SDK for iOS, um die fünf häufigsten Ortswahrscheinlichkeiten basierend auf dem aktuellen Standort des Nutzers zu ermitteln. Die Liste wird dann in einer UITableView
präsentiert. Wenn der Nutzer einen Ort auswählt, wird eine Markierung auf der Karte eingefügt.
- Eine Liste mit Orten abrufen, die wahrscheinlich in ein
UITableView
-Objekt eingefügt werden sollen. Hier kann der Nutzer den Ort auswählen, an dem er sich gerade befindet. - Öffnen Sie eine neue Ansicht, um dem Nutzer Orte zu präsentieren, die wahrscheinlich von Ihnen stammen. Wenn der Nutzer auf „Ort abrufen“ tippt, wird eine neue Ansicht geöffnet. Dem Nutzer wird eine Liste mit möglichen Orten angezeigt, aus denen er auswählen kann. Die Funktion
prepare
aktualisiertPlacesViewController
mit der Liste der aktuell wahrscheinlichen Orte und wird automatisch aufgerufen, wenn ein Übergang ausgeführt wird. - Füllen Sie in
PlacesViewController
die Tabelle mit der Liste der Orte, die am wahrscheinlichsten sind, und verwenden Sie die Delegate-ErweiterungUITableViewDataSource
. - Verwalten Sie die Auswahl des Nutzers mithilfe der Delegaterweiterung
UITableViewDelegate
.
Swift
// Populate the array with the list of likely places. func listLikelyPlaces() { // Clean up from previous sessions. likelyPlaces.removeAll() let placeFields: GMSPlaceField = [.name, .coordinate] placesClient.findPlaceLikelihoodsFromCurrentLocation(withPlaceFields: placeFields) { (placeLikelihoods, error) in guard error == nil else { // TODO: Handle the error. print("Current Place error: \(error!.localizedDescription)") return } guard let placeLikelihoods = placeLikelihoods else { print("No places found.") return } // Get likely places and add to the list. for likelihood in placeLikelihoods { let place = likelihood.place self.likelyPlaces.append(place) } } }
Objective-C
// Populate the array with the list of likely places. - (void) listLikelyPlaces { // Clean up from previous sessions. likelyPlaces = [NSMutableArray array]; GMSPlaceField placeFields = GMSPlaceFieldName | GMSPlaceFieldCoordinate; [placesClient findPlaceLikelihoodsFromCurrentLocationWithPlaceFields:placeFields callback:^(NSArray<GMSPlaceLikelihood *> * _Nullable likelihoods, NSError * _Nullable error) { if (error != nil) { // TODO: Handle the error. NSLog(@"Current Place error: %@", error.localizedDescription); return; } if (likelihoods == nil) { NSLog(@"No places found."); return; } for (GMSPlaceLikelihood *likelihood in likelihoods) { GMSPlace *place = likelihood.place; [likelyPlaces addObject:place]; } }]; }
Swift
// Prepare the segue. override func prepare(for segue: UIStoryboardSegue, sender: Any?) { if segue.identifier == "segueToSelect" { if let nextViewController = segue.destination as? PlacesViewController { nextViewController.likelyPlaces = likelyPlaces } } }
Objective-C
// Prepare the segue. - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { if ([segue.identifier isEqualToString:@"segueToSelect"]) { if ([segue.destinationViewController isKindOfClass:[PlacesViewController class]]) { PlacesViewController *placesViewController = (PlacesViewController *)segue.destinationViewController; placesViewController.likelyPlaces = likelyPlaces; } } }
Swift
// Populate the table with the list of most likely places. extension PlacesViewController: UITableViewDataSource { func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return likelyPlaces.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: cellReuseIdentifier, for: indexPath) let collectionItem = likelyPlaces[indexPath.row] cell.textLabel?.text = collectionItem.name return cell } }
Objective-C
#pragma mark - UITableViewDataSource - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return self.likelyPlaces.count; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { return [tableView dequeueReusableCellWithIdentifier:cellReuseIdentifier forIndexPath:indexPath]; } @end
Swift
class PlacesViewController: UIViewController { // ... // Pass the selected place to the new view controller. override func prepare(for segue: UIStoryboardSegue, sender: Any?) { if segue.identifier == "unwindToMain" { if let nextViewController = segue.destination as? MapViewController { nextViewController.selectedPlace = selectedPlace } } } } // Respond when a user selects a place. extension PlacesViewController: UITableViewDelegate { func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { selectedPlace = likelyPlaces[indexPath.row] performSegue(withIdentifier: "unwindToMain", sender: self) } // Adjust cell height to only show the first five items in the table // (scrolling is disabled in IB). func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { return self.tableView.frame.size.height/5 } // Make table rows display at proper height if there are less than 5 items. func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat { if (section == tableView.numberOfSections - 1) { return 1 } return 0 } }
Objective-C
@interface PlacesViewController () <UITableViewDataSource, UITableViewDelegate> // ... -(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { } #pragma mark - UITableViewDelegate // Respond when a user selects a place. -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { self.selectedPlace = [self.likelyPlaces objectAtIndex:indexPath.row]; [self performSegueWithIdentifier:@"unwindToMain" sender:self]; } // Adjust cell height to only show the first five items in the table // (scrolling is disabled in IB). -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { return self.tableView.frame.size.height/5; } // Make table rows display at proper height if there are less than 5 items. -(CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section { if (section == tableView.numberOfSections - 1) { return 1; } return 0; }
Markierung zur Karte hinzufügen
Trifft der Nutzer eine Auswahl, kehren Sie mit einem Abspann-Übergang zur vorherigen Ansicht zurück und fügen Sie die Markierung der Karte hinzu. Die IBAction unwindToMain
wird automatisch aufgerufen, wenn Sie zum Controller der Hauptansicht zurückkehren.
Swift
// Update the map once the user has made their selection. @IBAction func unwindToMain(segue: UIStoryboardSegue) { // Clear the map. mapView.clear() // Add a marker to the map. if let place = selectedPlace { let marker = GMSMarker(position: place.coordinate) marker.title = selectedPlace?.name marker.snippet = selectedPlace?.formattedAddress marker.map = mapView } listLikelyPlaces() }
Objective-C
// Update the map once the user has made their selection. - (void) unwindToMain:(UIStoryboardSegue *)segue { // Clear the map. [mapView clear]; // Add a marker to the map. if (selectedPlace != nil) { GMSMarker *marker = [GMSMarker markerWithPosition:selectedPlace.coordinate]; marker.title = selectedPlace.name; marker.snippet = selectedPlace.formattedAddress; marker.map = mapView; } [self listLikelyPlaces]; }
Glückwunsch! Sie haben eine iOS-App erstellt, mit der Nutzer ihren aktuellen Ort auswählen und das Ergebnis auf einer Google-Karte anzeigen lassen können. Sie wissen jetzt, wie Sie das Places SDK for iOS, das Maps SDK for iOS und das Apple Core Location Framework verwenden.