เลือกสถานที่ปัจจุบันและแสดงรายละเอียดบนแผนที่
บทแนะนำนี้แสดงการสร้างแอป iOS ที่ดึงข้อมูลตำแหน่งปัจจุบันของอุปกรณ์ ระบุตำแหน่งที่เป็นไปได้ แจ้งให้ผู้ใช้เลือกตำแหน่งที่ตรงที่สุด และแสดงเครื่องหมายบนแผนที่สำหรับตำแหน่งที่เลือก
เหมาะสำหรับผู้ที่มีพื้นฐานหรือความรู้ระดับกลางเกี่ยวกับ Swift หรือ Objective-C และมีความรู้ทั่วไปเกี่ยวกับ Xcode อ่านคู่มือนักพัฒนาซอฟต์แวร์เพื่อดูคู่มือขั้นสูงในการสร้างแผนที่
คุณจะใช้บทแนะนำนี้เพื่อสร้างแผนที่ต่อไปนี้ เครื่องหมายแผนที่จะอยู่ในซานฟรานซิสโก รัฐแคลิฟอร์เนีย แต่จะย้ายไปอยู่ที่ใดก็ได้ที่อุปกรณ์หรือเครื่องจำลองอยู่
บทแนะนํานี้ใช้ Places SDK สําหรับ iOS, Maps SDK สําหรับ iOS และ เฟรมเวิร์ก Apple Core Location
รับโค้ด
โคลนหรือดาวน์โหลดที่เก็บตัวอย่าง Google Maps สำหรับ iOS จาก GitHubหรือคลิกปุ่มต่อไปนี้เพื่อดาวน์โหลดซอร์สโค้ด
MapViewController
Swift
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)") } }
Objective-C
#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
PlacesViewController
Swift
import UIKit import GooglePlaces 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 } } // 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
#import "PlacesViewController.h" @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; } #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 Package Manager
คุณติดตั้ง Maps SDK สำหรับ iOS ได้โดยใช้ Swift Package Manager
- ตรวจสอบว่าคุณได้นำการอ้างอิง Maps SDK สำหรับ iOS ที่มีอยู่ออกแล้ว
- เปิดหน้าต่างเทอร์มินัลและไปที่ไดเรกทอรี
tutorials/current-place-on-map
-
ตรวจสอบว่าปิดเวิร์กスペース Xcode แล้ว แล้วเรียกใช้คำสั่งต่อไปนี้
sudo gem install cocoapods-deintegrate cocoapods-clean pod deintegrate pod cache clean --all rm Podfile rm current-place-on-map.xcworkspace
- เปิดโปรเจ็กต์ Xcode แล้วลบ Podfile
- เพิ่ม Places และ Maps SDK
- ไปที่ไฟล์ > เพิ่มแพ็กเกจ Dependency
- ป้อน https://github.com/googlemaps/ios-places-sdk เป็น URL แล้วกด Enter เพื่อดึงข้อมูลแพ็กเกจ แล้วคลิกเพิ่มแพ็กเกจ
- ป้อน https://github.com/googlemaps/ios-maps-sdk เป็น URL แล้วกด Enter เพื่อดึงข้อมูลแพ็กเกจ แล้วคลิกเพิ่มแพ็กเกจ
- คุณอาจต้องรีเซ็ตแคชแพ็กเกจโดยใช้ไฟล์ > แพ็กเกจ > รีเซ็ตแคชแพ็กเกจ
ใช้ CocoaPods
- ดาวน์โหลดและติดตั้ง Xcode เวอร์ชัน 15.0 ขึ้นไป
- หากยังไม่มี CocoaPods ให้ติดตั้งใน macOS โดยเรียกใช้คำสั่งต่อไปนี้จากเทอร์มินัล
sudo gem install cocoapods
- ไปที่ไดเรกทอรี
tutorials/current-place-on-map
- เรียกใช้คำสั่ง
pod install
ซึ่งจะติดตั้ง Maps and Places SDK ที่ระบุไว้ในPodfile
พร้อมกับไลบรารีที่เกี่ยวข้อง - เรียกใช้
pod outdated
เพื่อเปรียบเทียบเวอร์ชันพ็อดที่ติดตั้งกับอัปเดตใหม่ หากตรวจพบเวอร์ชันใหม่ ให้เรียกใช้pod update
เพื่ออัปเดตPodfile
และติดตั้ง SDK เวอร์ชันล่าสุด โปรดดูรายละเอียดเพิ่มเติมในคู่มือ CocoaPods - เปิด (ดับเบิลคลิก) ไฟล์ current-place-on-map.xcworkspace ของโปรเจ็กต์เพื่อเปิดใน Xcode คุณต้องใช้ไฟล์
.xcworkspace
เพื่อเปิดโปรเจ็กต์
รับคีย์ API และเปิดใช้ API ที่จําเป็น
คุณต้องมีคีย์ Google API ที่ได้รับอนุญาตให้ใช้ Maps SDK สําหรับ iOS และ Places API จึงจะทําตามบทแนะนํานี้ได้
- ทําตามวิธีการในเริ่มต้นใช้งาน Google Maps Platform เพื่อตั้งค่าบัญชีสําหรับการเรียกเก็บเงินและโปรเจ็กต์ที่เปิดใช้ทั้ง 2 ผลิตภัณฑ์นี้
- ทําตามวิธีการในหัวข้อรับคีย์ API เพื่อสร้างคีย์ API สําหรับโปรเจ็กต์การพัฒนาที่คุณตั้งค่าไว้ก่อนหน้านี้
เพิ่มคีย์ API ลงในแอปพลิเคชัน
เพิ่มคีย์ API ลงใน AppDelegate.swift
ดังนี้
- โปรดทราบว่ามีการเพิ่มคำสั่งการนําเข้าต่อไปนี้ลงในไฟล์แล้ว
import GooglePlaces import GoogleMaps
- แก้ไขบรรทัดต่อไปนี้ใน
application(_:didFinishLaunchingWithOptions:)
เมธอด โดยแทนที่ YOUR_API_KEY ด้วยคีย์ API ของคุณGMSPlacesClient.provideAPIKey("YOUR_API_KEY") GMSServices.provideAPIKey("YOUR_API_KEY")
สร้างและเรียกใช้แอป
- เชื่อมต่ออุปกรณ์ iOS กับคอมพิวเตอร์ หรือเลือกโปรแกรมจำลองจากเมนูป๊อปอัปรูปแบบ Xcode
- หากคุณใช้อุปกรณ์ ให้ตรวจสอบว่าได้เปิดใช้บริการตำแหน่งแล้ว หากคุณใช้เครื่องจำลอง ให้เลือกสถานที่จากเมนูฟีเจอร์
- ใน Xcode ให้คลิกตัวเลือกเมนู Product/Run (หรือไอคอนปุ่มเล่น)
- Xcode จะสร้างแอป จากนั้นเรียกใช้แอปในอุปกรณ์หรือในเครื่องจำลอง
- คุณควรเห็นแผนที่ที่มีเครื่องหมายจำนวนหนึ่งอยู่ตรงกลางตำแหน่งปัจจุบันของคุณ
การแก้ปัญหา:
- หากไม่เห็นแผนที่ ให้ตรวจสอบว่าคุณได้รับคีย์ API แล้วและเพิ่มลงในแอปแล้วตามที่อธิบายไว้ข้างต้น ตรวจสอบคอนโซลการแก้ไขข้อบกพร่องของ Xcode เพื่อดูข้อความแสดงข้อผิดพลาดเกี่ยวกับคีย์ API
- หากคุณจํากัดคีย์ API ตามตัวระบุกลุ่ม iOS ให้แก้ไขคีย์เพื่อเพิ่มตัวระบุกลุ่มสําหรับแอป
com.google.examples.current-place-on-map
- แผนที่จะไม่แสดงอย่างถูกต้องหากคำขอสิทธิ์สำหรับบริการหาตำแหน่งถูกปฏิเสธ
- หากคุณใช้อุปกรณ์ ให้ไปที่การตั้งค่า/ทั่วไป/ความเป็นส่วนตัว/บริการตำแหน่ง แล้วเปิดใช้บริการตำแหน่งอีกครั้ง
- หากคุณใช้โปรแกรมจำลอง ให้ไปที่โปรแกรมจำลอง/รีเซ็ตเนื้อหาและการตั้งค่า...
- ตรวจสอบว่าคุณมีการเชื่อมต่อ Wi-Fi หรือ GPS ที่สัญญาณดี
- หากแอปเปิดขึ้นแต่ไม่มีแผนที่แสดง ให้ตรวจสอบว่าคุณได้อัปเดต Info.plist ของโปรเจ็กต์ด้วยสิทธิ์เข้าถึงตำแหน่งที่เหมาะสมแล้ว ดูข้อมูลเพิ่มเติมเกี่ยวกับการจัดการสิทธิ์ได้ที่คำแนะนำการขอสิทธิ์เข้าถึงตำแหน่งในแอปด้านล่าง
- ใช้เครื่องมือแก้ไขข้อบกพร่อง Xcode เพื่อดูบันทึกและแก้ไขข้อบกพร่องของแอป
ทําความเข้าใจโค้ด
ส่วนนี้ของบทแนะนำจะอธิบายส่วนสําคัญที่สุดของแอปcurrent-place-on-map เพื่อช่วยให้คุณเข้าใจวิธีสร้างแอปที่คล้ายกัน
แอป current-place-on-map มีตัวควบคุมมุมมอง 2 รายการ ได้แก่ รายการที่แสดงแผนที่ซึ่งแสดงสถานที่ที่ผู้ใช้เลือกอยู่ในปัจจุบัน และรายการที่แสดงรายการสถานที่ที่เป็นไปได้ให้ผู้ใช้เลือก โปรดทราบว่าตัวควบคุมมุมมองแต่ละรายการจะมีตัวแปรเดียวกันสำหรับการติดตามรายการสถานที่ที่เป็นไปได้ (likelyPlaces
) และเพื่อระบุการเลือกของผู้ใช้ (selectedPlace
) การนำทางระหว่างมุมมองทำได้โดยใช้ segue
การขอสิทธิ์เข้าถึงตำแหน่ง
แอปของคุณต้องแจ้งให้ผู้ใช้ให้ความยินยอมในการใช้บริการหาตำแหน่ง โดยให้ใส่คีย์ NSLocationAlwaysUsageDescription
ในไฟล์ Info.plist
ของแอป และตั้งค่าของคีย์แต่ละรายการเป็นสตริงที่อธิบายวิธีที่แอปตั้งใจจะใช้ข้อมูลตําแหน่ง
การตั้งค่าเครื่องมือจัดการตำแหน่ง
ใช้ CLLocationManager เพื่อค้นหาตำแหน่งปัจจุบันของอุปกรณ์และขอการอัปเดตเป็นประจำเมื่ออุปกรณ์ย้ายไปยังตำแหน่งใหม่ บทแนะนำนี้จะแสดงรหัสที่คุณต้องใช้ในการรับตำแหน่งของอุปกรณ์ ดูรายละเอียดเพิ่มเติมได้ที่คู่มือการระบุตําแหน่งของผู้ใช้ในเอกสารประกอบสําหรับนักพัฒนาแอปของ Apple
- ประกาศตัวจัดการตำแหน่ง ตําแหน่งปัจจุบัน มุมมองแผนที่ ไคลเอ็นต์สถานที่ และระดับการซูมเริ่มต้นที่ระดับคลาส
- เริ่มต้นตัวจัดการตำแหน่งและ
GMSPlacesClient
ในviewDidLoad()
- ประกาศตัวแปรเพื่อเก็บรายการสถานที่ที่เป็นไปได้และสถานที่ที่ผู้ใช้เลือก
- เพิ่มผู้รับมอบสิทธิ์เพื่อจัดการเหตุการณ์สําหรับเครื่องมือจัดการตําแหน่งโดยใช้อนุประโยคส่วนขยาย
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); }
การเพิ่มแผนที่
สร้างแผนที่และเพิ่มลงในมุมมองใน viewDidLoad()
ในตัวควบคุมมุมมองหลัก แผนที่จะซ่อนอยู่จนกว่าจะได้รับการอัปเดตตำแหน่ง (การอัปเดตตำแหน่งจะจัดการใน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;
แจ้งให้ผู้ใช้เลือกตำแหน่งปัจจุบัน
ใช้ Places SDK สําหรับ iOS เพื่อรับสถานที่ที่มีแนวโน้มมากที่สุด 5 แห่งตามตําแหน่งปัจจุบันของผู้ใช้ และแสดงรายการในUITableView
เมื่อผู้ใช้เลือกสถานที่ ให้เพิ่มเครื่องหมายลงในแผนที่
- รับรายการสถานที่ที่เป็นไปได้เพื่อป้อนข้อมูล
UITableView
ซึ่งผู้ใช้สามารถเลือกสถานที่ที่ตนอยู่ - เปิดมุมมองใหม่เพื่อแสดงสถานที่ที่เป็นไปได้ต่อผู้ใช้ เมื่อผู้ใช้แตะ "รับสถานที่" เราจะเปลี่ยนไปที่มุมมองใหม่และแสดงรายการสถานที่ที่เป็นไปได้ให้ผู้ใช้เลือก ฟังก์ชัน
prepare
จะอัปเดตPlacesViewController
ด้วยรายการสถานที่ปัจจุบันที่เป็นไปได้ และระบบจะเรียกใช้โดยอัตโนมัติเมื่อมีการเรียกใช้ Segue - ใน
PlacesViewController
ให้กรอกข้อมูลในตารางโดยใช้รายการสถานที่ที่เป็นไปได้มากที่สุดโดยใช้ส่วนขยายตัวแทนUITableViewDataSource
- จัดการการเลือกของผู้ใช้สําหรับ
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; }
การเพิ่มเครื่องหมายลงในแผนที่
เมื่อผู้ใช้เลือกแล้ว ให้ใช้ Segue แบบย้อนกลับเพื่อกลับไปที่มุมมองก่อนหน้า และเพิ่มเครื่องหมายลงในแผนที่ ระบบจะเรียก unwindToMain
IBAction โดยอัตโนมัติเมื่อกลับไปยังตัวควบคุมมุมมองหลัก
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]; }
ยินดีด้วย คุณได้สร้างแอป iOS ที่อนุญาตให้ผู้ใช้เลือกตำแหน่งปัจจุบันของตน และแสดงผลลัพธ์บน Google Maps ในระหว่างการดำเนินการนี้ คุณได้เรียนรู้วิธีใช้ Places SDK สำหรับ iOS, Maps SDK สำหรับ iOS และ เฟรมเวิร์ก Apple Core Location