Wybieranie bieżącego miejsca i pokazywanie szczegółów na mapie
Ten samouczek przedstawia tworzenie aplikacji na iOS, która pobiera bieżącą lokalizację urządzenia, identyfikuje prawdopodobne lokalizacje, prosi użytkownika o wybranie najbardziej dopasowanej i wyświetla znacznik mapy dla wybranej lokalizacji.
Jest odpowiedni dla osób, które znają język Swift lub Objective-C na początku lub na poziomie średnio zaawansowanym, a także ogólną znajomość Xcode. Zaawansowany przewodnik tworzenia map znajdziesz w przewodniku dla programistów.
Za pomocą tego samouczka utworzysz następującą mapę. Znacznik mapy znajduje się w San Francisco w stanie Kalifornia, ale zostanie przeniesiony tam, gdzie znajduje się urządzenie lub symulator.
Ten samouczek korzysta z pakietu SDK Miejsc na iOS, Maps SDK na iOS i platformy Apple Core Location.
Pobierz kod
Skopiuj lub pobierz repozytorium przykładowych Map Google na iOS z GitHuba.Możesz też kliknąć następujący przycisk, aby pobrać kod źródłowy:
Kontroler Swift MapView
/* * 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)") } }
kontroler widoku miejsc Swift
/* * 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 } }
kontroler widoku mapy Obj-C
// // 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
kontroler widoku miejsc Obj-C
// 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
Rozpocznij
Menedżer pakietów Swift
Pakiet Maps SDK na iOS można zainstalować za pomocą menedżera pakietów Swift.
- Upewnij się, że wszystkie zależności od pakietu Maps SDK na iOS zostały usunięte.
- Otwórz okno terminala i przejdź do katalogu
tutorials/current-place-on-map
. -
Zamknij obszar roboczy Xcode i uruchom te polecenia:
sudo gem install cocoapods-deintegrate cocoapods-clean pod deintegrate pod cache clean --all rm Podfile rm current-place-on-map.xcworkspace
- Otwórz projekt Xcode i usuń plik podfile.
- Dodaj pakiety SDK Miejsc i Map Google:
- Kliknij Plik > Dodaj zależności pakietu.
- Wpisz URL https://github.com/googlemaps/ios-places-sdk, naciśnij Enter, aby pobrać pakiet, i kliknij Dodaj pakiet.
- Wpisz https://github.com/googlemaps/ios-maps-sdk jako adres URL, naciśnij Enter, aby pobrać pakiet, i kliknij Dodaj pakiet.
- Może być konieczne zresetowanie pamięci podręcznej pakietów. W tym celu kliknij Plik > Pakiety > Zresetuj pamięć podręczną pakietów.
Używaj CocoaPods
- Pobierz i zainstaluj Xcode w wersji 15.0 lub nowszej.
- Jeśli nie masz jeszcze aplikacji CocoaPods, zainstaluj ją w systemie macOS, uruchamiając w terminalu to polecenie:
sudo gem install cocoapods
- Przejdź do katalogu
tutorials/current-place-on-map
. - Uruchom polecenie
pod install
. Spowoduje to zainstalowanie pakietów SDK Map i miejsc określonych w zasadziePodfile
wraz z wszystkimi zależnościami. - Uruchom
pod outdated
, aby porównać wersję zainstalowanego poda z wszystkimi nowymi aktualizacjami. Po wykryciu nowej wersji uruchom poleceniepod update
, aby zaktualizowaćPodfile
i zainstalować najnowszy pakiet SDK. Więcej informacji znajdziesz w przewodniku CocoaPods. - Otwórz (dwukrotnie kliknij) plik current-place-on-map.xcworkspace projektu, aby otworzyć go w Xcode. Aby otworzyć projekt, musisz użyć pliku
.xcworkspace
.
Uzyskiwanie klucza interfejsu API i włączanie niezbędnych interfejsów API
Aby ukończyć ten samouczek, potrzebujesz klucza interfejsu API Google z uprawnieniami do korzystania z pakietu SDK Maps na iOS i interfejsu Places API.
- Postępuj zgodnie z instrukcjami opisanymi w artykule Pierwsze kroki z Google Maps Platform, aby skonfigurować konto rozliczeniowe i projekt włączony w obu tych usługach.
- Wykonaj instrukcje uzyskiwania klucza interfejsu API, aby utworzyć klucz interfejsu API dla skonfigurowanego wcześniej projektu deweloperskiego.
Dodawanie klucza interfejsu API do aplikacji
Dodaj klucz interfejsu API do AppDelegate.swift
w ten sposób:
- Pamiętaj, że do pliku dodano tę instrukcję importu:
import GooglePlaces import GoogleMaps
- Zmień ten wiersz w metodzie
application(_:didFinishLaunchingWithOptions:)
, zastępując YOUR_API_KEY swoim kluczem interfejsu API:GMSPlacesClient.provideAPIKey("YOUR_API_KEY") GMSServices.provideAPIKey("YOUR_API_KEY")
Tworzenie i uruchamianie aplikacji
- Podłącz urządzenie z iOS do komputera lub wybierz symulator z menu schematu Xcode.
- Jeśli używasz urządzenia, upewnij się, że są włączone usługi lokalizacyjne. Jeśli używasz symulatora, wybierz lokalizację z menu Funkcje.
- W Xcode kliknij opcję menu Product/Run (Produkt/Uruchom) (lub ikonę przycisku odtwarzania).
- Xcode kompiluje aplikację, a następnie uruchamia ją na urządzeniu lub w symulatorze.
- Powinna się wyświetlić mapa z szeregiem znaczników wyśrodkowanych wokół Twojej bieżącej lokalizacji.
Rozwiązywanie problemów:
- Jeśli nie widzisz mapy, sprawdź, czy udało Ci się uzyskać klucz interfejsu API i dodać go do aplikacji w sposób opisany powyżej. Sprawdź, czy w konsoli debugowania Xcode są komunikaty o błędach dotyczące klucza interfejsu API.
- Jeśli klucz interfejsu API został ograniczony przez identyfikator pakietu na iOS, edytuj klucz, aby dodać identyfikator pakietu aplikacji:
com.google.examples.current-place-on-map
. - Jeśli prośba o uprawnienia dla usług lokalizacyjnych zostanie odrzucona, mapa nie będzie wyświetlać się prawidłowo.
- Jeśli używasz urządzenia, otwórz Ustawienia/Ogólne/Prywatność/Usługi lokalizacji i ponownie włącz usługi lokalizacyjne.
- Jeśli używasz symulatora, otwórz Simulator/Reset Content and Settings (Symulator/Resetuj zawartość i ustawienia...)
- Upewnij się, że masz dobre połączenie Wi-Fi lub GPS.
- Jeśli aplikacja się uruchomi, ale nie wyświetli się mapa, sprawdź, czy plik Info.plist projektu został zaktualizowany na odpowiednie uprawnienia do lokalizacji. Więcej informacji o obsłudze uprawnień znajdziesz w przewodniku po prośbach o dostęp do lokalizacji w aplikacji poniżej.
- Użyj narzędzi do debugowania Xcode, aby wyświetlać logi i debugować aplikację.
Zrozumienie kodu
W tej części samouczka objaśniamy najważniejsze elementy aplikacji current-place-on-map, aby pomóc Ci stworzyć podobną aplikację.
Aplikacja current-place-on-map ma 2 kontrolery widoku: jeden wyświetla mapę z wybranym aktualnie miejscem użytkownika i drugą z listą prawdopodobnych miejsc do wyboru. Pamiętaj, że każdy kontroler widoku danych ma te same zmienne do śledzenia listy prawdopodobnych miejsc (likelyPlaces
) i do wskazywania wyboru użytkownika (selectedPlace
). Nawigacja między widokami ułatwia się za pomocą seg.
Proszę o dostęp do lokalizacji
Aplikacja musi poprosić użytkownika o zgodę na korzystanie z usług lokalizacyjnych. Aby to zrobić, umieść klucz NSLocationAlwaysUsageDescription
w pliku Info.plist
dotyczącym aplikacji i ustaw wartość każdego klucza na ciąg znaków, który opisuje, jak aplikacja będzie używać danych o lokalizacji.
Konfigurowanie menedżera lokalizacji
Za pomocą funkcji CLLocationManager możesz znaleźć bieżącą lokalizację urządzenia i poprosić o regularne aktualizacje, gdy urządzenie przenosi się w nowe miejsce. Ten samouczek zawiera kod potrzebny do uzyskania lokalizacji urządzenia. Aby dowiedzieć się więcej, zobacz przewodnik na temat uzyskiwania lokalizacji użytkownika w dokumentacji Apple dla deweloperów.
- Zadeklaruj menedżera lokalizacji, bieżącą lokalizację, widok mapy, klienta miejsc i domyślny poziom powiększenia na poziomie klasy.
- Zainicjuj menedżera lokalizacji i
GMSPlacesClient
wviewDidLoad()
. - Zadeklaruj zmienne, które będą przechowywać listę prawdopodobnych miejsc oraz miejsca wybranego przez użytkownika.
- Dodaj przedstawicieli, którzy będą obsługiwać zdarzenia dla menedżera lokalizacji, używając klauzuli rozszerzenia.
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); }
Dodawanie mapy
Utwórz mapę i dodaj ją do widoku w viewDidLoad()
w głównym kontrolerze widoku. Mapa pozostanie ukryta, dopóki nie zostanie pobrana aktualizacja lokalizacji (aktualizacje lokalizacji są obsługiwane w rozszerzeniu CLLocationManagerDelegate
).
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;
Wyświetlanie użytkownikowi prośby o wybranie aktualnego miejsca
Użyj pakietu Places SDK na iOS, aby poznać 5 największych prawdopodobieństw miejsc na podstawie bieżącej lokalizacji użytkownika, i zaprezentuj listę w narzędziu UITableView
. Gdy użytkownik wybierze miejsce, dodaj znacznik do mapy.
- Uzyskaj listę potencjalnych miejsc, w których można wypełnić pole
UITableView
, a użytkownik może wybrać miejsce, w którym się aktualnie znajduje. - Otwórz nowy widok, aby przedstawić użytkownikowi prawdopodobne miejsca. Kliknięcie przycisku „Pobierz miejsce” powoduje przejście do nowego widoku i wyświetlenie listy możliwych miejsc do wyboru. Funkcja
prepare
aktualizuje sięPlacesViewController
o listę aktualnych prawdopodobnych miejsc i jest automatycznie wywoływana podczas przechodzenia. - W usłudze
PlacesViewController
wypełnij tabelę za pomocą listy najbardziej prawdopodobnej lokalizacji za pomocą rozszerzeniaUITableViewDataSource
do przekazywania dostępu. - Obsługuj wybór użytkownika za pomocą rozszerzenia przekazania dostępu
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; }
Dodawanie znacznika do mapy
Gdy użytkownik dokona wyboru, użyj funkcji relaksu, aby wrócić do poprzedniego widoku, i dodaj znacznik do mapy. Funkcja unwindToMain
IBAction jest wywoływana automatycznie po powrocie do głównego kontrolera widoku.
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]; }
Gratulacje! Masz aplikację na iOS, która pozwala użytkownikowi wybrać swoje aktualne miejsce i pokazuje wynik na mapie Google. W trakcie wykonywania tych czynności wiesz, jak korzystać z pakietu Places SDK na iOS, Maps SDK na iOS oraz platformy Apple Core Location.