انتخاب مکان فعلی و نمایش جزئیات روی نقشه

این آموزش، ساخت یک برنامه iOS را نشان می‌دهد که مکان فعلی دستگاه را بازیابی می‌کند، مکان‌های احتمالی را شناسایی می‌کند، از کاربر می‌خواهد بهترین مورد منطبق را انتخاب کند و یک نشانگر نقشه برای مکان انتخاب شده نمایش می‌دهد.

این برنامه برای کسانی که دانش اولیه یا متوسطی از Swift یا Objective-C و دانش عمومی از Xcode دارند، مناسب است. برای راهنمای پیشرفته ایجاد نقشه‌ها، راهنمای توسعه‌دهندگان را مطالعه کنید.

شما با استفاده از این آموزش نقشه زیر را ایجاد خواهید کرد. نشانگر نقشه در سانفرانسیسکو، کالیفرنیا قرار دارد، اما به هر جایی که دستگاه یا شبیه‌ساز قرار دارد، منتقل می‌شود.

این آموزش از Places SDK برای iOS ، Maps SDK برای iOS و فریم‌ورک Apple Core Location استفاده می‌کند.

کد را دریافت کنید

مخزن نمونه‌های iOS نقشه‌های گوگل را از گیت‌هاب کپی یا دانلود کنید.

روش دیگر، برای دانلود کد منبع روی دکمه زیر کلیک کنید:

کد رو بهم بده

کنترلر نمای نقشه

سویفت

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)")
  }
}
      

هدف-سی

#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

سویفت

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
  }
}
      

هدف-سی

#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
      

شروع کنید

مدیر بسته سوئیفت

کیت توسعه نرم‌افزار نقشه‌ها برای iOS را می‌توان با استفاده از Swift Package Manager نصب کرد.

  1. هرگونه SDK نقشه موجود برای وابستگی‌های iOS را حذف کنید.
  2. یک پنجره ترمینال باز کنید و به دایرکتوری tutorials/current-place-on-map بروید.
  3. فضای کاری Xcode خود را ببندید و دستورات زیر را اجرا کنید:
            sudo gem install cocoapods-deintegrate cocoapods-clean
            pod deintegrate
            pod cache clean --all
            rm Podfile
            rm current-place-on-map.xcworkspace
  4. پروژه Xcode خود را باز کنید و فایل podfile را حذف کنید.
  5. SDK های مکان ها و نقشه ها را اضافه کنید:
    1. به فایل > افزودن وابستگی‌های بسته بروید.
    2. آدرس https://github.com/googlemaps/ios-places-sdk را به عنوان URL وارد کنید، برای دریافت بسته، Enter را فشار دهید و روی Add Package کلیک کنید.
    3. آدرس https://github.com/googlemaps/ios-maps-sdk را به عنوان URL وارد کنید، برای دریافت بسته، Enter را فشار دهید و روی Add Package کلیک کنید.
  6. ممکن است لازم باشد حافظه پنهان بسته خود را با استفاده از File > Packages > Reset Package Cache بازنشانی کنید.

از کوکوپادز استفاده کنید

  1. Xcode نسخه ۱۶.۰ یا بالاتر را دانلود و نصب کنید.
  2. اگر CocoaPods را از قبل ندارید، با اجرای دستور زیر از ترمینال، آن را روی macOS نصب کنید:
    sudo gem install cocoapods
  3. به دایرکتوری tutorials/current-place-on-map بروید.
  4. دستور pod install را اجرا کنید. این دستور SDK های Maps و Places که در Podfile مشخص شده اند را به همراه هرگونه وابستگی نصب می کند.
  5. برای مقایسه نسخه نصب شده pod با هرگونه به‌روزرسانی جدید، pod outdated اجرا کنید. اگر نسخه جدیدی شناسایی شد، pod update اجرا کنید تا Podfile را به‌روزرسانی کرده و آخرین SDK را نصب کنید. برای جزئیات بیشتر، به راهنمای CocoaPods مراجعه کنید.
  6. برای باز کردن پروژه در Xcode، فایل current-place-on-map.xcworkspace را باز کنید (روی آن دوبار کلیک کنید). برای باز کردن پروژه باید از فایل .xcworkspace استفاده کنید.

یک کلید API دریافت کنید و API های لازم را فعال کنید

برای تکمیل این آموزش، به یک کلید API گوگل نیاز دارید که مجاز به استفاده از Maps SDK برای iOS و Places API باشد.

  1. برای تنظیم حساب پرداخت و فعال‌سازی پروژه با هر دوی این محصولات، دستورالعمل‌های « شروع به کار با پلتفرم نقشه‌های گوگل» را دنبال کنید.
  2. برای ایجاد کلید API برای پروژه توسعه‌ای که قبلاً راه‌اندازی کرده‌اید ، دستورالعمل‌های مربوط به دریافت کلید API را دنبال کنید.

کلید API را به برنامه خود اضافه کنید

کلید API خود را به صورت زیر به AppDelegate.swift خود اضافه کنید:

  1. توجه داشته باشید که عبارت import زیر به فایل اضافه شده است:
    import GooglePlaces
    import GoogleMaps
  2. خط زیر را در application(_:didFinishLaunchingWithOptions:) ویرایش کنید و YOUR_API_KEY را با کلید API خود جایگزین کنید:
    GMSPlacesClient.provideAPIKey("YOUR_API_KEY")
    GMSServices.provideAPIKey("YOUR_API_KEY")

برنامه خود را بسازید و اجرا کنید

  1. یک دستگاه iOS را به رایانه خود وصل کنید، یا یک شبیه‌ساز را از منوی طرح Xcode انتخاب کنید.
  2. اگر از دستگاه استفاده می‌کنید، مطمئن شوید که سرویس‌های موقعیت مکانی فعال هستند. اگر از شبیه‌ساز استفاده می‌کنید، از منوی ویژگی‌ها ، یک مکان را انتخاب کنید.
  3. در 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 دارای دو کنترلر نما است: یکی برای نمایش نقشه‌ای که مکان انتخاب شده توسط کاربر را نشان می‌دهد و دیگری برای ارائه لیستی از مکان‌های احتمالی برای انتخاب به کاربر. توجه داشته باشید که هر کنترلر نما متغیرهای یکسانی برای ردیابی لیست مکان‌های احتمالی ( likelyPlaces ) و برای نشان دادن انتخاب کاربر ( selectedPlace ) دارد. پیمایش بین نماها با استفاده از segueها انجام می‌شود.

درخواست مجوز مکان

برنامه شما باید از کاربر برای استفاده از سرویس‌های موقعیت مکانی رضایت بخواهد. برای انجام این کار، کلید NSLocationAlwaysUsageDescription را در فایل Info.plist برنامه قرار دهید و مقدار هر کلید را به رشته‌ای تنظیم کنید که نحوه استفاده برنامه از داده‌های موقعیت مکانی را شرح دهد.

مدیر مکان را تنظیم کنید

از CLLocationManager برای یافتن مکان فعلی دستگاه و درخواست به‌روزرسانی‌های منظم هنگام انتقال دستگاه به مکان جدید استفاده کنید. این آموزش کدی را که برای دریافت مکان دستگاه نیاز دارید، ارائه می‌دهد. برای جزئیات بیشتر، به راهنمای دریافت مکان کاربر در مستندات توسعه‌دهندگان اپل مراجعه کنید.

  1. مدیر مکان، مکان فعلی، نمای نقشه، کلاینت مکان‌ها و سطح بزرگنمایی پیش‌فرض را در سطح کلاس تعریف کنید.
  2. سویفت

    var locationManager: CLLocationManager!
    var currentLocation: CLLocation?
    var mapView: GMSMapView!
    var placesClient: GMSPlacesClient!
    var preciseLocationZoomLevel: Float = 15.0
    var approximateLocationZoomLevel: Float = 10.0
          

    هدف-سی

    CLLocationManager *locationManager;
    CLLocation * _Nullable currentLocation;
    GMSMapView *mapView;
    GMSPlacesClient *placesClient;
    float preciseLocationZoomLevel;
    float approximateLocationZoomLevel;
          
  3. مقداردهی اولیه‌ی location manager و GMSPlacesClient در viewDidLoad()
  4. سویفت

    // Initialize the location manager.
    locationManager = CLLocationManager()
    locationManager.desiredAccuracy = kCLLocationAccuracyBest
    locationManager.requestWhenInUseAuthorization()
    locationManager.distanceFilter = 50
    locationManager.startUpdatingLocation()
    locationManager.delegate = self
    
    placesClient = GMSPlacesClient.shared()
          

    هدف-سی

    // Initialize the location manager.
    locationManager = [[CLLocationManager alloc] init];
    locationManager.desiredAccuracy = kCLLocationAccuracyBest;
    [locationManager requestWhenInUseAuthorization];
    locationManager.distanceFilter = 50;
    [locationManager startUpdatingLocation];
    locationManager.delegate = self;
    
    placesClient = [GMSPlacesClient sharedClient];
          
  5. متغیرهایی را برای نگهداری لیست مکان‌های احتمالی و مکان انتخاب شده توسط کاربر تعریف کنید.
  6. سویفت

    // An array to hold the list of likely places.
    var likelyPlaces: [GMSPlace] = []
    
    // The currently selected place.
    var selectedPlace: GMSPlace?
          

    هدف-سی

    // An array to hold the list of likely places.
    NSMutableArray<GMSPlace *> *likelyPlaces;
    
    // The currently selected place.
    GMSPlace * _Nullable selectedPlace;
          
  7. با استفاده از یک بند الحاقی، نمایندگانی را برای مدیریت رویدادها برای مدیر مکان اضافه کنید.
  8. سویفت

    // 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)")
      }
    }
          

    هدف-سی

    // 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 مدیریت می‌شوند).

سویفت

// 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
      

هدف-سی

// 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 استفاده کنید تا بر اساس موقعیت فعلی کاربر، پنج مکان برتر با احتمال حضور را دریافت کنید و لیست را در یک UITableView ارائه دهید. وقتی کاربر مکانی را انتخاب می‌کند، یک نشانگر به نقشه اضافه کنید.

  1. فهرستی از مکان‌های احتمالی برای پر کردن یک UITableView دریافت کنید، که از آن طریق کاربر می‌تواند مکانی را که در آن قرار دارد انتخاب کند.
  2. سویفت

    // 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)
        }
      }
    }
          

    هدف-سی

    // 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];
        }
      }];
    }
          
  3. یک نمای جدید باز کنید تا مکان‌های احتمالی را به کاربر ارائه دهید. وقتی کاربر روی "دریافت مکان" ضربه می‌زند، ما به یک نمای جدید segue می‌کنیم و لیستی از مکان‌های ممکن برای انتخاب را به کاربر نشان می‌دهیم. تابع prepare PlacesViewController با لیست مکان‌های احتمالی فعلی به‌روزرسانی می‌کند و هنگام اجرای segue به طور خودکار فراخوانی می‌شود.
  4. سویفت

    // 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
        }
      }
    }
          

    هدف-سی

    // 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;
        }
      }
    }
          
  5. در PlacesViewController ، جدول را با استفاده از فهرست مکان‌های محتمل، و با استفاده از افزونه‌ی نماینده‌ی UITableViewDataSource ، پر کنید.
  6. سویفت

    // 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
      }
    }
          

    هدف-سی

    #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
          
  7. انتخاب کاربر را با استفاده از افزونه‌ی نماینده‌ی UITableViewDelegate مدیریت کنید.
  8. سویفت

    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
      }
    }
          

    هدف-سی

    @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;
    }
          

اضافه کردن نشانگر به نقشه

وقتی کاربر انتخابی انجام می‌دهد، از یک unwind segue برای بازگشت به نمای قبلی استفاده کنید و نشانگر را به نقشه اضافه کنید. unwindToMain IBAction به طور خودکار پس از بازگشت به کنترلر نمای اصلی فراخوانی می‌شود.

سویفت

// 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()
}
      

هدف-سی

// 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 ساخته‌اید که به کاربر اجازه می‌دهد مکان فعلی خود را انتخاب کند و نتیجه را روی نقشه گوگل نشان می‌دهد. در حین انجام این کار، یاد گرفته‌اید که چگونه از Places SDK برای iOS ، Maps SDK برای iOS و چارچوب Apple Core Location استفاده کنید.