เลือกสถานที่ปัจจุบันและแสดงรายละเอียดบนแผนที่
บทแนะนำนี้แสดงการสร้างแอป iOS ที่ดึงข้อมูลตำแหน่งปัจจุบันของอุปกรณ์ ระบุตำแหน่งที่เป็นไปได้ แจ้งให้ผู้ใช้เลือกตำแหน่งที่ตรงที่สุด และแสดงเครื่องหมายบนแผนที่สำหรับตำแหน่งที่เลือก
เหมาะสำหรับผู้ที่มีพื้นฐานหรือความรู้ระดับกลางเกี่ยวกับ Swift หรือ Objective-C และมีความรู้ทั่วไปเกี่ยวกับ Xcode อ่านคู่มือนักพัฒนาซอฟต์แวร์เพื่อดูคู่มือขั้นสูงในการสร้างแผนที่
คุณจะใช้บทแนะนำนี้เพื่อสร้างแผนที่ต่อไปนี้ เครื่องหมายบนแผนที่จะอยู่ในซานฟรานซิสโก แคลิฟอร์เนีย แต่จะย้ายไปยังตำแหน่งที่อุปกรณ์หรือเครื่องจำลองอยู่
บทแนะนํานี้ใช้ Places SDK สําหรับ iOS, Maps SDK สําหรับ iOS และเฟรมเวิร์กตําแหน่งหลักของ Apple
รับโค้ด
โคลนหรือดาวน์โหลดที่เก็บตัวอย่างของ 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 และ Places SDK ที่ระบุไว้ในPodfile
พร้อมกับ Dependency ทั้งหมด - เรียกใช้
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 ให้คลิกตัวเลือกเมนูผลิตภัณฑ์/เรียกใช้ (หรือไอคอนปุ่มเล่น)
- 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