الإكمال التلقائي للأماكن

تعرض خدمة الإكمال التلقائي في Places SDK for iOS توقعات بشأن الأماكن استجابةً لطلبات بحث المستخدمين. أثناء كتابة المستخدم، تعرض خدمة الإكمال التلقائي اقتراحات لأماكن، مثل الأنشطة التجارية والعناوين ورموز المواقع المفتوحة ونقاط الاهتمام.

يمكنك إضافة ميزة "الإكمال التلقائي" إلى تطبيقك بالطرق التالية:

إضافة عنصر تحكّم في واجهة المستخدم للإكمال التلقائي

عنصر التحكّم في واجهة مستخدم الإكمال التلقائي هو مربّع حوار بحث يتضمّن وظيفة إكمال تلقائي. أثناء إدخال المستخدم لعبارات البحث، يعرض عنصر التحكّم قائمة بالأماكن المتوقّعة للاختيار من بينها. عندما يحدّد المستخدم مكانًا، يتم عرض مثيل GMSPlace، ويمكن لتطبيقك بعد ذلك استخدامه للحصول على تفاصيل حول المكان المحدّد.

يمكنك إضافة عنصر التحكّم في واجهة مستخدم الإكمال التلقائي إلى تطبيقك بالطرق التالية:

إضافة عنصر تحكّم بملء الشاشة

استخدِم عنصر التحكّم في ملء الشاشة عندما تريد سياقًا مشروطًا، حيث تحل واجهة مستخدم الإكمال التلقائي محل واجهة مستخدم تطبيقك مؤقتًا إلى أن يحدّد المستخدم اختياره. يتم توفير هذه الوظيفة من خلال فئة GMSAutocompleteViewController. عندما يختار المستخدم مكانًا، يتلقّى تطبيقك ردّ اتصال.

لإضافة عنصر تحكّم بملء الشاشة إلى تطبيقك، اتّبِع الخطوات التالية:

  1. أنشئ عنصر واجهة مستخدم في تطبيقك الرئيسي لتشغيل عنصر التحكّم في واجهة المستخدم الخاص بالإكمال التلقائي، مثل معالج اللمس على UIButton.
  2. نفِّذ بروتوكول GMSAutocompleteViewControllerDelegate في وحدة التحكّم في العرض الرئيسي.
  3. أنشئ مثيلاً من GMSAutocompleteViewController وعيِّن وحدة التحكّم في العرض الرئيسي كخاصية مفوَّضة.
  4. أنشئ GMSPlaceField لتحديد أنواع بيانات الأماكن التي سيتم عرضها.
  5. أضِف GMSAutocompleteFilter لتقييد الاستعلام بنوع معيّن من الأماكن.
  6. اعرض GMSAutocompleteViewController باستخدام [self presentViewController...].
  7. تعامَل مع اختيار المستخدم في طريقة التفويض didAutocompleteWithPlace.
  8. تجاهل أداة التحكّم في طرق التفويض didAutocompleteWithPlace وdidFailAutocompleteWithError وwasCancelled.

يوضّح المثال التالي إحدى الطرق المحتملة لتشغيل GMSAutocompleteViewController استجابةً لنقر المستخدم على زر.

Swift

import UIKit
import GooglePlaces

class ViewController: UIViewController {

  override func viewDidLoad() {
    makeButton()
  }

  // Present the Autocomplete view controller when the button is pressed.
  @objc func autocompleteClicked(_ sender: UIButton) {
    let autocompleteController = GMSAutocompleteViewController()
    autocompleteController.delegate = self

    // Specify the place data types to return.
    let fields: GMSPlaceField = GMSPlaceField(rawValue: UInt(GMSPlaceField.name.rawValue) |
      UInt(GMSPlaceField.placeID.rawValue))!
    autocompleteController.placeFields = fields

    // Specify a filter.
    let filter = GMSAutocompleteFilter()
    filter.types = [.address]
    autocompleteController.autocompleteFilter = filter

    // Display the autocomplete view controller.
    present(autocompleteController, animated: true, completion: nil)
  }

  // Add a button to the view.
  func makeButton() {
    let btnLaunchAc = UIButton(frame: CGRect(x: 5, y: 150, width: 300, height: 35))
    btnLaunchAc.backgroundColor = .blue
    btnLaunchAc.setTitle("Launch autocomplete", for: .normal)
    btnLaunchAc.addTarget(self, action: #selector(autocompleteClicked), for: .touchUpInside)
    self.view.addSubview(btnLaunchAc)
  }

}

extension ViewController: GMSAutocompleteViewControllerDelegate {

  // Handle the user's selection.
  func viewController(_ viewController: GMSAutocompleteViewController, didAutocompleteWith place: GMSPlace) {
    print("Place name: \(place.name)")
    print("Place ID: \(place.placeID)")
    print("Place attributions: \(place.attributions)")
    dismiss(animated: true, completion: nil)
  }

  func viewController(_ viewController: GMSAutocompleteViewController, didFailAutocompleteWithError error: Error) {
    // TODO: handle the error.
    print("Error: ", error.localizedDescription)
  }

  // User canceled the operation.
  func wasCancelled(_ viewController: GMSAutocompleteViewController) {
    dismiss(animated: true, completion: nil)
  }

  // Turn the network activity indicator on and off again.
  func didRequestAutocompletePredictions(_ viewController: GMSAutocompleteViewController) {
    UIApplication.shared.isNetworkActivityIndicatorVisible = true
  }

  func didUpdateAutocompletePredictions(_ viewController: GMSAutocompleteViewController) {
    UIApplication.shared.isNetworkActivityIndicatorVisible = false
  }

}

Objective-C

#import "ViewController.h"
@import GooglePlaces;

@interface ViewController () <GMSAutocompleteViewControllerDelegate>

@end

@implementation ViewController {
  GMSAutocompleteFilter *_filter;
}

-   (void)viewDidLoad {
  [super viewDidLoad];
  [self makeButton];
}

  // Present the autocomplete view controller when the button is pressed.
-   (void)autocompleteClicked {
  GMSAutocompleteViewController *acController = [[GMSAutocompleteViewController alloc] init];
  acController.delegate = self;

  // Specify the place data types to return.
  GMSPlaceField fields = (GMSPlaceFieldName | GMSPlaceFieldPlaceID);
  acController.placeFields = fields;

  // Specify a filter.
  _filter = [[GMSAutocompleteFilter alloc] init];
  _filter.types = @[ kGMSPlaceTypeBank ];
  acController.autocompleteFilter = _filter;

  // Display the autocomplete view controller.
  [self presentViewController:acController animated:YES completion:nil];
}

  // Add a button to the view.
-   (void)makeButton{
  UIButton *btnLaunchAc = [UIButton buttonWithType:UIButtonTypeCustom];
  [btnLaunchAc addTarget:self
             action:@selector(autocompleteClicked) forControlEvents:UIControlEventTouchUpInside];
  [btnLaunchAc setTitle:@"Launch autocomplete" forState:UIControlStateNormal];
  btnLaunchAc.frame = CGRectMake(5.0, 150.0, 300.0, 35.0);
  btnLaunchAc.backgroundColor = [UIColor blueColor];
  [self.view addSubview:btnLaunchAc];
}

  // Handle the user's selection.
-   (void)viewController:(GMSAutocompleteViewController *)viewController
didAutocompleteWithPlace:(GMSPlace *)place {
  [self dismissViewControllerAnimated:YES completion:nil];
  // Do something with the selected place.
  NSLog(@"Place name %@", place.name);
  NSLog(@"Place ID %@", place.placeID);
  NSLog(@"Place attributions %@", place.attributions.string);
}

-   (void)viewController:(GMSAutocompleteViewController *)viewController
didFailAutocompleteWithError:(NSError *)error {
  [self dismissViewControllerAnimated:YES completion:nil];
  // TODO: handle the error.
  NSLog(@"Error: %@", [error description]);
}

  // User canceled the operation.
-   (void)wasCancelled:(GMSAutocompleteViewController *)viewController {
  [self dismissViewControllerAnimated:YES completion:nil];
}

  // Turn the network activity indicator on and off again.
-   (void)didRequestAutocompletePredictions:(GMSAutocompleteViewController *)viewController {
  [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
}

-   (void)didUpdateAutocompletePredictions:(GMSAutocompleteViewController *)viewController {
  [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
}

@end

إضافة أداة التحكّم في النتائج

استخدِم أداة التحكّم في النتائج عندما تريد المزيد من التحكّم في واجهة مستخدم إدخال النص. يُبدّل أداة التحكّم في النتائج بشكل ديناميكي إمكانية رؤية قائمة النتائج استنادًا إلى تركيز واجهة المستخدم على الإدخال.

لإضافة أداة تحكّم في النتائج إلى تطبيقك، اتّبِع الخطوات التالية:

  1. أنشئ GMSAutocompleteResultsViewController.
    1. نفِّذ بروتوكول GMSAutocompleteResultsViewControllerDelegate في وحدة التحكّم في العرض الرئيسي، وعيِّن وحدة التحكّم في العرض الرئيسي كخاصية مفوَّضة.
  2. أنشئ عنصر UISearchController، مع تمرير GMSAutocompleteResultsViewController كوسيطة لوحدة التحكّم في النتائج.
  3. اضبط GMSAutocompleteResultsViewController كسمة searchResultsUpdater الخاصة بـ UISearchController.
  4. أضِف searchBar UISearchController إلى واجهة مستخدم تطبيقك.
  5. تعامَل مع اختيار المستخدم في طريقة التفويض didAutocompleteWithPlace.

هناك عدة طرق لوضع شريط البحث الخاص بـ UISearchController في واجهة مستخدم تطبيقك:

إضافة شريط بحث إلى شريط التنقّل

يوضّح مثال الرمز البرمجي التالي كيفية إضافة أداة تحكّم في النتائج وإضافة searchBar إلى شريط التنقّل والتعامل مع اختيار المستخدم:

Swift

class ViewController: UIViewController {

  var resultsViewController: GMSAutocompleteResultsViewController?
  var searchController: UISearchController?
  var resultView: UITextView?

  override func viewDidLoad() {
    super.viewDidLoad()

    resultsViewController = GMSAutocompleteResultsViewController()
    resultsViewController?.delegate = self

    searchController = UISearchController(searchResultsController: resultsViewController)
    searchController?.searchResultsUpdater = resultsViewController

    // Put the search bar in the navigation bar.
    searchController?.searchBar.sizeToFit()
    navigationItem.titleView = searchController?.searchBar

    // When UISearchController presents the results view, present it in
    // this view controller, not one further up the chain.
    definesPresentationContext = true

    // Prevent the navigation bar from being hidden when searching.
    searchController?.hidesNavigationBarDuringPresentation = false
  }
}

// Handle the user's selection.
extension ViewController: GMSAutocompleteResultsViewControllerDelegate {
  func resultsController(_ resultsController: GMSAutocompleteResultsViewController,
                         didAutocompleteWith place: GMSPlace) {
    searchController?.isActive = false
    // Do something with the selected place.
    print("Place name: \(place.name)")
    print("Place address: \(place.formattedAddress)")
    print("Place attributions: \(place.attributions)")
  }

  func resultsController(_ resultsController: GMSAutocompleteResultsViewController,
                         didFailAutocompleteWithError error: Error){
    // TODO: handle the error.
    print("Error: ", error.localizedDescription)
  }

  // Turn the network activity indicator on and off again.
  func didRequestAutocompletePredictions(_ viewController: GMSAutocompleteViewController) {
    UIApplication.shared.isNetworkActivityIndicatorVisible = true
  }

  func didUpdateAutocompletePredictions(_ viewController: GMSAutocompleteViewController) {
    UIApplication.shared.isNetworkActivityIndicatorVisible = false
  }
}

Objective-C

-   (void)viewDidLoad {
  _resultsViewController = [[GMSAutocompleteResultsViewController alloc] init];
  _resultsViewController.delegate = self;

  _searchController = [[UISearchController alloc]
                       initWithSearchResultsController:_resultsViewController];
  _searchController.searchResultsUpdater = _resultsViewController;

  // Put the search bar in the navigation bar.
  [_searchController.searchBar sizeToFit];
  self.navigationItem.titleView = _searchController.searchBar;

  // When UISearchController presents the results view, present it in
  // this view controller, not one further up the chain.
  self.definesPresentationContext = YES;

  // Prevent the navigation bar from being hidden when searching.
  _searchController.hidesNavigationBarDuringPresentation = NO;
}

// Handle the user's selection.
-   (void)resultsController:(GMSAutocompleteResultsViewController *)resultsController
  didAutocompleteWithPlace:(GMSPlace *)place {
    _searchController.active = NO;
    // Do something with the selected place.
    NSLog(@"Place name %@", place.name);
    NSLog(@"Place address %@", place.formattedAddress);
    NSLog(@"Place attributions %@", place.attributions.string);
}

-   (void)resultsController:(GMSAutocompleteResultsViewController *)resultsController
didFailAutocompleteWithError:(NSError *)error {
  [self dismissViewControllerAnimated:YES completion:nil];
  // TODO: handle the error.
  NSLog(@"Error: %@", [error description]);
}

// Turn the network activity indicator on and off again.
-   (void)didRequestAutocompletePredictionsForResultsController:
    (GMSAutocompleteResultsViewController *)resultsController {
  [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
}

-   (void)didUpdateAutocompletePredictionsForResultsController:
    (GMSAutocompleteResultsViewController *)resultsController {
  [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
}

إضافة شريط بحث إلى أعلى طريقة عرض

يوضّح مثال الرمز البرمجي التالي كيفية إضافة searchBar إلى أعلى إحدى طرق العرض.

Swift

import UIKit
import GooglePlaces

class ViewController: UIViewController {

  var resultsViewController: GMSAutocompleteResultsViewController?
  var searchController: UISearchController?
  var resultView: UITextView?

  override func viewDidLoad() {
    super.viewDidLoad()

    resultsViewController = GMSAutocompleteResultsViewController()
    resultsViewController?.delegate = self

    searchController = UISearchController(searchResultsController: resultsViewController)
    searchController?.searchResultsUpdater = resultsViewController

    let subView = UIView(frame: CGRect(x: 0, y: 65.0, width: 350.0, height: 45.0))

    subView.addSubview((searchController?.searchBar)!)
    view.addSubview(subView)
    searchController?.searchBar.sizeToFit()
    searchController?.hidesNavigationBarDuringPresentation = false

    // When UISearchController presents the results view, present it in
    // this view controller, not one further up the chain.
    definesPresentationContext = true
  }
}

// Handle the user's selection.
extension ViewController: GMSAutocompleteResultsViewControllerDelegate {
  func resultsController(_ resultsController: GMSAutocompleteResultsViewController,
                         didAutocompleteWith place: GMSPlace) {
    searchController?.isActive = false
    // Do something with the selected place.
    print("Place name: \(place.name)")
    print("Place address: \(place.formattedAddress)")
    print("Place attributions: \(place.attributions)")
  }

  func resultsController(_ resultsController: GMSAutocompleteResultsViewController,
                         didFailAutocompleteWithError error: Error){
    // TODO: handle the error.
    print("Error: ", error.localizedDescription)
  }

  // Turn the network activity indicator on and off again.
  func didRequestAutocompletePredictions(forResultsController resultsController: GMSAutocompleteResultsViewController) {
    UIApplication.shared.isNetworkActivityIndicatorVisible = true
  }

  func didUpdateAutocompletePredictions(forResultsController resultsController: GMSAutocompleteResultsViewController) {
    UIApplication.shared.isNetworkActivityIndicatorVisible = false
  }
}

Objective-C

-   (void)viewDidLoad {
    [super viewDidLoad];

    _resultsViewController = [[GMSAutocompleteResultsViewController alloc] init];
    _resultsViewController.delegate = self;

    _searchController = [[UISearchController alloc]
                             initWithSearchResultsController:_resultsViewController];
    _searchController.searchResultsUpdater = _resultsViewController;

    UIView *subView = [[UIView alloc] initWithFrame:CGRectMake(0, 65.0, 250, 50)];

    [subView addSubview:_searchController.searchBar];
    [_searchController.searchBar sizeToFit];
    [self.view addSubview:subView];

    // When UISearchController presents the results view, present it in
    // this view controller, not one further up the chain.
    self.definesPresentationContext = YES;
}

// Handle the user's selection.
-   (void)resultsController:(GMSAutocompleteResultsViewController *)resultsController
didAutocompleteWithPlace:(GMSPlace *)place {
  [self dismissViewControllerAnimated:YES completion:nil];
  // Do something with the selected place.
  NSLog(@"Place name %@", place.name);
  NSLog(@"Place address %@", place.formattedAddress);
  NSLog(@"Place attributions %@", place.attributions.string);
}

-   (void)resultsController:(GMSAutocompleteResultsViewController *)resultsController
didFailAutocompleteWithError:(NSError *)error {
  [self dismissViewControllerAnimated:YES completion:nil];
  // TODO: handle the error.
  NSLog(@"Error: %@", [error description]);
}

// Turn the network activity indicator on and off again.
-   (void)didRequestAutocompletePredictionsForResultsController:
    (GMSAutocompleteResultsViewController *)resultsController {
  [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
}

-   (void)didUpdateAutocompletePredictionsForResultsController:
    (GMSAutocompleteResultsViewController *)resultsController {
  [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
}

بشكل تلقائي، يؤدي النقر على UISearchController إلى إخفاء شريط التنقل أثناء العرض التقديمي (يمكن إيقاف هذه الميزة). في الحالات التي يكون فيها شريط التنقّل مرئيًا وغير شفاف، لا يضبط UISearchController موضع العنصر بشكل صحيح.

استخدِم الرمز التالي كحلّ بديل:

Swift

navigationController?.navigationBar.translucent = false
searchController?.hidesNavigationBarDuringPresentation = false

// This makes the view area include the nav bar even though it is opaque.
// Adjust the view placement down.
self.extendedLayoutIncludesOpaqueBars = true
self.edgesForExtendedLayout = .top

Objective-C

self.navigationController.navigationBar.translucent = NO;
_searchController.hidesNavigationBarDuringPresentation = NO;

// This makes the view area include the nav bar even though it is opaque.
// Adjust the view placement down.
self.extendedLayoutIncludesOpaqueBars = YES;
self.edgesForExtendedLayout = UIRectEdgeTop;

إضافة شريط بحث باستخدام نتائج النافذة المنبثقة

يوضّح مثال الرمز التالي كيفية وضع شريط بحث على الجانب الأيسر من شريط التنقّل، وعرض النتائج في نافذة منبثقة.

Swift

import UIKit
import GooglePlaces

class ViewController: UIViewController {

  var resultsViewController: GMSAutocompleteResultsViewController?
  var searchController: UISearchController?
  var resultView: UITextView?

  override func viewDidLoad() {
    super.viewDidLoad()

    resultsViewController = GMSAutocompleteResultsViewController()
    resultsViewController?.delegate = self

    searchController = UISearchController(searchResultsController: resultsViewController)
    searchController?.searchResultsUpdater = resultsViewController

    // Add the search bar to the right of the nav bar,
    // use a popover to display the results.
    // Set an explicit size as we don't want to use the entire nav bar.
    searchController?.searchBar.frame = (CGRect(x: 0, y: 0, width: 250.0, height: 44.0))
    navigationItem.rightBarButtonItem = UIBarButtonItem(customView: (searchController?.searchBar)!)

    // When UISearchController presents the results view, present it in
    // this view controller, not one further up the chain.
    definesPresentationContext = true

    // Keep the navigation bar visible.
    searchController?.hidesNavigationBarDuringPresentation = false
    searchController?.modalPresentationStyle = .popover
  }
}
// Handle the user's selection.
extension ViewController: GMSAutocompleteResultsViewControllerDelegate {
  func resultsController(_ resultsController: GMSAutocompleteResultsViewController,
                         didAutocompleteWith place: GMSPlace) {
    searchController?.isActive = false
    // Do something with the selected place.
    print("Place name: \(place.name)")
    print("Place address: \(place.formattedAddress)")
    print("Place attributions: \(place.attributions)")
  }

  func resultsController(_ resultsController: GMSAutocompleteResultsViewController,
                         didFailAutocompleteWithError error: Error){
    // TODO: handle the error.
    print("Error: ", error.localizedDescription)
  }

  // Turn the network activity indicator on and off again.
  func didRequestAutocompletePredictions(forResultsController resultsController: GMSAutocompleteResultsViewController) {
    UIApplication.shared.isNetworkActivityIndicatorVisible = true
  }

  func didUpdateAutocompletePredictions(forResultsController resultsController: GMSAutocompleteResultsViewController) {
    UIApplication.shared.isNetworkActivityIndicatorVisible = false
  }
}

Objective-C

-   (void)viewDidLoad {
  [super viewDidLoad];

  _resultsViewController = [[GMSAutocompleteResultsViewController alloc] init];
  _resultsViewController.delegate = self;

  _searchController = [[UISearchController alloc]
                           initWithSearchResultsController:_resultsViewController];
  _searchController.searchResultsUpdater = _resultsViewController;

  // Add the search bar to the right of the nav bar,
  // use a popover to display the results.
  // Set an explicit size as we don't want to use the entire nav bar.
  _searchController.searchBar.frame = CGRectMake(0, 0, 250.0f, 44.0f);
  self.navigationItem.rightBarButtonItem =
  [[UIBarButtonItem alloc] initWithCustomView:_searchController.searchBar];

  // When UISearchController presents the results view, present it in
  // this view controller, not one further up the chain.
  self.definesPresentationContext = YES;

  // Keep the navigation bar visible.
  _searchController.hidesNavigationBarDuringPresentation = NO;

  _searchController.modalPresentationStyle = UIModalPresentationPopover;
}

// Handle the user's selection.
-   (void)resultsController:(GMSAutocompleteResultsViewController *)resultsController
didAutocompleteWithPlace:(GMSPlace *)place {
  [self dismissViewControllerAnimated:YES completion:nil];
  NSLog(@"Place name %@", place.name);
  NSLog(@"Place address %@", place.formattedAddress);
  NSLog(@"Place attributions %@", place.attributions.string);
}

-   (void)resultsController:(GMSAutocompleteResultsViewController *)resultsController
didFailAutocompleteWithError:(NSError *)error {
  [self dismissViewControllerAnimated:YES completion:nil];
  // TODO: handle the error.
  NSLog(@"Error: %@", [error description]);
}

// Turn the network activity indicator on and off again.
-   (void)didRequestAutocompletePredictionsForResultsController:
    (GMSAutocompleteResultsViewController *)resultsController {
  [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
}

-   (void)didUpdateAutocompletePredictionsForResultsController:
    (GMSAutocompleteResultsViewController *)resultsController {
  [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
}

استخدام مصدر بيانات جدول

إذا كان تطبيقك يتضمّن واجهة مستخدم مخصّصة لنص البحث، يمكنك استخدام فئة GMSAutocompleteTableDataSource لإدارة عرض جدول النتائج في وحدة التحكّم في العرض.

لاستخدام GMSAutocompleteTableDataSource كمصدر بيانات ومفوّض UITableView في وحدة التحكّم في العرض، اتّبِع الخطوات التالية:

  1. نفِّذ البروتوكولَين GMSAutocompleteTableDataSourceDelegate وUISearchBarDelegate في وحدة التحكّم في العرض.
  2. أنشئ مثيلاً من GMSAutocompleteTableDataSource وعيِّن وحدة التحكّم في العرض كخاصية مفوَّضة.
  3. اضبط GMSAutocompleteTableDataSource كمصدر بيانات وسمات تفويض لمثيل UITableView في وحدة التحكّم في العرض.
  4. في معالج إدخال نص البحث، استدعِ sourceTextHasChanged على GMSAutocompleteTableDataSource.
    1. تعامَل مع اختيار المستخدم في طريقة التفويض didAutocompleteWithPlace.
  5. تجاهل وحدة التحكّم في طرق التفويض didAutocompleteWithPlace وdidFailAutocompleteWithError وwasCancelled.

يوضّح مثال الرمز البرمجي التالي كيفية استخدام فئة GMSAutocompleteTableDataSource لعرض جدول UIViewController عندما تتم إضافة UISearchBar بشكل منفصل.

Swift

// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

import GooglePlaces
import UIKit

class PlaceAutocompleteViewController: UIViewController {

  private var tableView: UITableView!
  private var tableDataSource: GMSAutocompleteTableDataSource!

  override func viewDidLoad() {
    super.viewDidLoad()

    let searchBar = UISearchBar(frame: CGRect(x: 0, y: 20, width: self.view.frame.size.width, height: 44.0))
    searchBar.delegate = self
    view.addSubview(searchBar)

    tableDataSource = GMSAutocompleteTableDataSource()
    tableDataSource.delegate = self

    tableView = UITableView(frame: CGRect(x: 0, y: 64, width: self.view.frame.size.width, height: self.view.frame.size.height - 44))
    tableView.delegate = tableDataSource
    tableView.dataSource = tableDataSource

    view.addSubview(tableView)
  }
}

extension PlaceAutocompleteViewController: UISearchBarDelegate {
  func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
    // Update the GMSAutocompleteTableDataSource with the search text.
    tableDataSource.sourceTextHasChanged(searchText)
  }
}

extension PlaceAutocompleteViewController: GMSAutocompleteTableDataSourceDelegate {
  func didUpdateAutocompletePredictions(for tableDataSource: GMSAutocompleteTableDataSource) {
    // Turn the network activity indicator off.
    UIApplication.shared.isNetworkActivityIndicatorVisible = false
    // Reload table data.
    tableView.reloadData()
  }

  func didRequestAutocompletePredictions(for tableDataSource: GMSAutocompleteTableDataSource) {
    // Turn the network activity indicator on.
    UIApplication.shared.isNetworkActivityIndicatorVisible = true
    // Reload table data.
    tableView.reloadData()
  }

  func tableDataSource(_ tableDataSource: GMSAutocompleteTableDataSource, didAutocompleteWith place: GMSPlace) {
    // Do something with the selected place.
    print("Place name: \(place.name)")
    print("Place address: \(place.formattedAddress)")
    print("Place attributions: \(place.attributions)")
  }

  func tableDataSource(_ tableDataSource: GMSAutocompleteTableDataSource, didFailAutocompleteWithError error: Error) {
    // Handle the error.
    print("Error: \(error.localizedDescription)")
  }

  func tableDataSource(_ tableDataSource: GMSAutocompleteTableDataSource, didSelect prediction: GMSAutocompletePrediction) -> Bool {
    return true
  }
}

      

Objective-C

// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#import "PlaceAutocompleteViewController.h"
@import GooglePlaces;
@import UIKit;

@interface PlaceAutocompleteViewController () <GMSAutocompleteTableDataSourceDelegate, UISearchBarDelegate>

@end

@implementation PlaceAutocompleteViewController {
  UITableView *tableView;
  GMSAutocompleteTableDataSource *tableDataSource;
}

- (void)viewDidLoad {
  [super viewDidLoad];

  UISearchBar *searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0, 20, self.view.frame.size.width, 44)];
  searchBar.delegate = self;

  [self.view addSubview:searchBar];

  tableDataSource = [[GMSAutocompleteTableDataSource alloc] init];
  tableDataSource.delegate = self;

  tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 64, self.view.frame.size.width, self.view.frame.size.height - 44)];
  tableView.delegate = tableDataSource;
  tableView.dataSource = tableDataSource;

  [self.view addSubview:tableView];
}

#pragma mark - GMSAutocompleteTableDataSourceDelegate

- (void)didUpdateAutocompletePredictionsForTableDataSource:(GMSAutocompleteTableDataSource *)tableDataSource {
  // Turn the network activity indicator off.
  UIApplication.sharedApplication.networkActivityIndicatorVisible = NO;

  // Reload table data.
  [tableView reloadData];
}

- (void)didRequestAutocompletePredictionsForTableDataSource:(GMSAutocompleteTableDataSource *)tableDataSource {
  // Turn the network activity indicator on.
  UIApplication.sharedApplication.networkActivityIndicatorVisible = YES;

  // Reload table data.
  [tableView reloadData];
}

- (void)tableDataSource:(GMSAutocompleteTableDataSource *)tableDataSource didAutocompleteWithPlace:(GMSPlace *)place {
  // Do something with the selected place.
  NSLog(@"Place name: %@", place.name);
  NSLog(@"Place address: %@", place.formattedAddress);
  NSLog(@"Place attributions: %@", place.attributions);
}

- (void)tableDataSource:(GMSAutocompleteTableDataSource *)tableDataSource didFailAutocompleteWithError:(NSError *)error {
  // Handle the error
  NSLog(@"Error %@", error.description);
}

- (BOOL)tableDataSource:(GMSAutocompleteTableDataSource *)tableDataSource didSelectPrediction:(GMSAutocompletePrediction *)prediction {
  return YES;
}

#pragma mark - UISearchBarDelegate

- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
  // Update the GMSAutocompleteTableDataSource with the search text.
  [tableDataSource sourceTextHasChanged:searchText];
}

@end

      

تخصيص ألوان النص والخلفية

يمكنك ضبط ألوان جميع النصوص والخلفيات في عنصر التحكّم في واجهة المستخدم الخاصة بميزة الإكمال التلقائي، وذلك لجعل الأداة تتطابق مع المظهر المرئي لتطبيقك بشكل أكبر. هناك طريقتان لضبط ألوان عناصر التحكّم في واجهة المستخدم:

  • من خلال استخدام بروتوكول UIAppearance المضمّن في نظام التشغيل iOS لتصميم عناصر التحكّم في واجهة المستخدم على مستوى العالم حيثما أمكن ذلك. تنطبق هذه الإعدادات على العديد من عناصر التحكّم في واجهة المستخدم، ولكن ليس على جميعها.
  • باستخدام طرق حزمة SDK في فئات التطبيقات المصغّرة لضبط الخصائص التي لا يتوافق معها بروتوكول UIAppearance

عادةً، سيستخدم تطبيقك مزيجًا من بروتوكول UIAppearance وطُرق حزمة SDK. يوضّح الرسم البياني التالي العناصر التي يمكن تنسيقها:

ألوان عنصر التحكّم في واجهة مستخدم الإكمال التلقائي

يسرد الجدول التالي جميع عناصر واجهة المستخدم، ويشير إلى كيفية تصميم كل عنصر (بروتوكول UIAppearance أو طريقة حزمة SDK).

عنصر واجهة المستخدم الطريقة إرشادات متعلّقة بالموضة
لون شريط التنقّل (الخلفية) بروتوكول UIAppearance الاتصال بـ "setBarTintColor" من خلال خادم وكيل على UINavigationBar
لون شريط التنقّل (علامة الإقحام في نص شريط البحث وزر "إلغاء") بروتوكول UIAppearance الاتصال بـ "setTintColor" من خلال خادم وكيل على UINavigationBar
لون نص شريط البحث بروتوكول UIAppearance اضبط NSForegroundColorAttributeName في searchBarTextAttributes.
لون درجة شريط البحث لا ينطبق شريط البحث شفاف، وسيتم عرضه كنسخة مظلّلة من شريط التنقّل.
لون نص العنصر النائب في شريط البحث (نص البحث التلقائي) بروتوكول UIAppearance اضبط NSForegroundColorAttributeName في placeholderAttributes.
النص الأساسي (يتم تطبيقه أيضًا على نص الخطأ والرسالة) طريقة حزمة تطوير البرامج (SDK) تواصل هاتفيًا مع "primaryTextColor".
تمييز النص الأساسي طريقة حزمة تطوير البرامج (SDK) تواصل هاتفيًا مع "primaryTextHighlightColor".
نص ثانوي طريقة حزمة تطوير البرامج (SDK) تواصل هاتفيًا مع "secondaryTextColor".
الخطأ ونص الرسالة طريقة حزمة تطوير البرامج (SDK) تواصل هاتفيًا مع "primaryTextColor".
خلفية خلية الجدول طريقة حزمة تطوير البرامج (SDK) تواصل هاتفيًا مع "tableCellBackgroundColor".
لون فاصل خلايا الجدول طريقة حزمة تطوير البرامج (SDK) تواصل هاتفيًا مع "tableCellSeparatorColor".
زر "إعادة المحاولة" طريقة حزمة تطوير البرامج (SDK) تواصل هاتفيًا مع "tintColor".
مؤشر النشاط (عجلة التقدّم) بروتوكول UIAppearance الاتصال بـ "setColor" من خلال خادم وكيل على UIActivityIndicatorView
شعار "تعمل بواسطة Google"، صورة سحابة حزينة لا ينطبق يتم اختيار الإصدار الأبيض أو الرمادي تلقائيًا استنادًا إلى تباين الخلفية.
رمزا العدسة المكبرة ومحو النص في حقل النص الخاص بشريط البحث لا ينطبق لتحديد النمط، استبدِل الصور التلقائية بصور باللون المطلوب.

استخدام بروتوكول UIAppearance

يمكنك استخدام بروتوكول UIAppearance للحصول على وكيل المظهر لعنصر واجهة مستخدم معيّن، والذي يمكنك استخدامه بعد ذلك لضبط لون عنصر واجهة المستخدم. عند إجراء تعديل، يتأثر كل مثيل لعنصر معيّن في واجهة المستخدم. على سبيل المثال، يغيّر المثال التالي على مستوى العالم لون نص الفئات UITextField إلى اللون الأخضر عندما تكون مضمّنة في UISearchBar:

[[UITextField appearanceWhenContainedIn:[UISearchBar class], nil]
    setDefaultTextAttributes:@{NSForegroundColorAttributeName:[UIColor greenColor]}];

لمزيد من المعلومات حول تحديد قيم الألوان، يُرجى الرجوع إلى مرجع فئة UIColor.

تعرض مقتطفات الرموز البرمجية التالية جميع أوامر الخادم الوكيل التي تحتاج إلى استخدامها لتصميم كل العناصر في عنصر التحكّم في واجهة مستخدم الإكمال التلقائي بملء الشاشة. أضِف هذا الرمز إلى طريقة didFinishLaunchingWithOptions في ملف Appdelegate.m:

// Define some colors.
UIColor *darkGray = [UIColor darkGrayColor];
UIColor *lightGray = [UIColor lightGrayColor];

// Navigation bar background.
[[UINavigationBar appearance] setBarTintColor:darkGray];
[[UINavigationBar appearance] setTintColor:lightGray];

// Color of typed text in the search bar.
NSDictionary *searchBarTextAttributes = @{
                                          NSForegroundColorAttributeName: lightGray,
                                          NSFontAttributeName : [UIFont systemFontOfSize:[UIFont systemFontSize]]
                                          };
[UITextField appearanceWhenContainedInInstancesOfClasses:@[[UISearchBar class]]]
    .defaultTextAttributes = searchBarTextAttributes;

// Color of the placeholder text in the search bar prior to text entry.
NSDictionary *placeholderAttributes = @{
                                        NSForegroundColorAttributeName: lightGray,
                                        NSFontAttributeName : [UIFont systemFontOfSize:[UIFont systemFontSize]]
                                        };

// Color of the default search text.
// NOTE: In a production scenario, "Search" would be a localized string.
NSAttributedString *attributedPlaceholder =
[[NSAttributedString alloc] initWithString:@"Search"
                                attributes:placeholderAttributes];
[UITextField appearanceWhenContainedInInstancesOfClasses:@[[UISearchBar class]]]
    .attributedPlaceholder = attributedPlaceholder;

// Color of the in-progress spinner.
[[UIActivityIndicatorView appearance] setColor:lightGray];

// To style the two image icons in the search bar (the magnifying glass
// icon and the 'clear text' icon), replace them with different images.
[[UISearchBar appearance] setImage:[UIImage imageNamed:@"custom_clear_x_high"]
                  forSearchBarIcon:UISearchBarIconClear
                            state:UIControlStateHighlighted];
[[UISearchBar appearance] setImage:[UIImage imageNamed:@"custom_clear_x"]
                  forSearchBarIcon:UISearchBarIconClear
                            state:UIControlStateNormal];
[[UISearchBar appearance] setImage:[UIImage imageNamed:@"custom_search"]
                    forSearchBarIcon:UISearchBarIconSearch
                            state:UIControlStateNormal];

// Color of selected table cells.
UIView *selectedBackgroundView = [[UIView alloc] init];
selectedBackgroundView.backgroundColor = [UIColor lightGrayColor];
[UITableViewCell appearanceWhenContainedIn:[GMSAutocompleteViewController class], nil]
    .selectedBackgroundView = selectedBackgroundView;

ضبط خصائص نمط عنصر التحكّم في واجهة مستخدم الإعدادات

تتضمّن مجموعة فرعية من عناصر التحكّم في واجهة المستخدم خصائص لا يتأثّر بها بروتوكول UIAppearance، وبالتالي يجب ضبطها مباشرةً. يوضّح مثال الرمز التالي كيفية تحديد ألوان الواجهة والخلفية وتطبيقها على عنصر تحكّم في واجهة المستخدم باسم acController. أضِف الرمز التالي إلى طريقة onLaunchClicked في ViewController.m:

UIColor *darkGray = [UIColor darkGrayColor];
UIColor *lightGray = [UIColor lightGrayColor];

acController.secondaryTextColor = [UIColor colorWithWhite:1.0f alpha:0.5f];
acController.primaryTextColor = lightGray;
acController.primaryTextHighlightColor = [UIColor grayColor];
acController.tableCellBackgroundColor = darkGray;
acController.tableCellSeparatorColor = lightGray;
acController.tintColor = lightGray;

الحصول على توقّعات الأماكن آليًا

يمكنك إنشاء واجهة مستخدم مخصّصة للبحث كبديل لواجهة المستخدم التي يوفّرها التطبيق المصغّر للإكمال التلقائي. ولإجراء ذلك، يجب أن يحصل تطبيقك على توقعات الأماكن آليًا. يمكن لتطبيقك الحصول على قائمة بأسماء الأماكن و/أو العناوين المتوقّعة بإحدى الطرق التالية:

سيتم الاتصال بالرقم GMSPlacesClient findAutocompletePredictionsFromQuery:

للحصول على قائمة بأسماء الأماكن و/أو العناوين المتوقّعة، عليك أولاً إنشاء مثيل GMSPlacesClient، ثم استدعاء طريقة GMSPlacesClient findAutocompletePredictionsFromQuery: باستخدام المَعلمات التالية:

  • autocompleteQuery سلسلة تحتوي على النص الذي كتبه المستخدم.
  • A GMSAutocompleteSessionToken، الذي يُستخدَم لتحديد كل جلسة على حدة. يجب أن يمرِّر تطبيقك الرمز المميز نفسه لكل طلب استدعاء خاص بالاقتراحات التلقائية، ثم يمرِّر هذا الرمز المميز مع معرّف المكان في طلب الاستدعاء اللاحق إلى fetchPlacefromPlaceID: لاسترداد تفاصيل المكان الذي اختاره المستخدم.
  • A GMSAutocompleteFilter إلى:
    • تحديد النتائج أو حصرها في منطقة معيّنة
    • حصر النتائج في نوع معيّن من الأماكن
    • GMSPlaceLocationBias/كائن Restriction الذي يوجّه النتائج إلى منطقة معيّنة يحدّدها نطاقا خطَّي الطول والعرض.
  • طريقة رد الاتصال للتعامل مع النتائج المقترَحة التي تم إرجاعها

تعرض أمثلة الرموز البرمجية أدناه طلبًا إلى findAutocompletePredictionsFromQuery:.

Swift

/**
 *   Create a new session token. Be sure to use the same token for calling
 *   findAutocompletePredictions, as well as the subsequent place details request.
 *   This ensures that the user's query and selection are billed as a single session.
 */
let token = GMSAutocompleteSessionToken.init()

// Create a type filter.
let filter = GMSAutocompleteFilter()
filter.types = [.bank]
filter.locationBias = GMSPlaceRectangularLocationOption( northEastBounds,
                                   southWestBounds);

placesClient?.findAutocompletePredictions(fromQuery: "cheesebu",

                                          filter: filter,
                                          sessionToken: token,
                                          callback: { (results, error) in
    if let error = error {
      print("Autocomplete error: \(error)")
      return
    }
    if let results = results {
      for result in results {
        print("Result \(result.attributedFullText) with placeID \(result.placeID)")
      }
    }
})

Objective-C

/**
 *   Create a new session token. Be sure to use the same token for calling
 *   findAutocompletePredictionsFromQuery:, as well as the subsequent place details request.
 *   This ensures that the user's query and selection are billed as a single session.
 */
GMSAutocompleteSessionToken *token = [[GMSAutocompleteSessionToken alloc] init];

// Create a type filter.
GMSAutocompleteFilter *_filter = [[GMSAutocompleteFilter alloc] init];
_filter.types = @[ kGMSPlaceTypeBank ];

[_placesClient findAutocompletePredictionsFromQuery:@"cheesebu"
filter:_filter sessionToken:token callback:^(NSArray<GMSAutocompletePrediction *> * _Nullable results, NSError * _Nullable error) {
  if (error != nil) {
    NSLog(@"An error occurred %@", [error localizedDescription]);
    return;
  }
  if (results != nil) {
    for (GMSAutocompletePrediction *result in results) {
      NSLog(@"Result %@ with PlaceID %@", result.attributedFullText, result.placeID);
    }
  }
}];

تستدعي واجهة برمجة التطبيقات طريقة رد الاتصال المحدّدة، وتمرّر إليها مصفوفة من عناصر GMSAutocompletePrediction.

يحتوي كل عنصر GMSAutocompletePrediction على المعلومات التالية:

  • attributedFullText – النص الكامل للتوقّع، على شكل NSAttributedString على سبيل المثال، "دار أوبرا سيدني، سيدني، نيو ساوث ويلز، أستراليا". يحتوي كل نطاق نصي يطابق إدخال المستخدم على سمة kGMSAutocompleteMatchAttribute. يمكنك استخدام هذه السمة لتسليط الضوء على النص المطابق في طلب بحث المستخدم، كما هو موضّح أدناه مثلاً.
  • استبدِل placeID برقم تعريف المكان المتوقّع. معرّف المكان هو معرّف نصي يحدّد مكانًا بشكل فريد. لمزيد من المعلومات حول معرّفات الأماكن، يُرجى الاطّلاع على نظرة عامة حول معرّف المكان.
  • distanceMeters: المسافة المستقيمة من origin المحدّد إلى الوجهة إذا لم يتم ضبط السمة origin، لن يتم عرض أي قيمة للمسافة.

يوضّح مثال الرمز البرمجي التالي كيفية تمييز أجزاء النتيجة التي تطابق النص في طلب بحث المستخدم بالخط الغامق، وذلك باستخدام enumerateAttribute:

Swift

let regularFont = UIFont.systemFont(ofSize: UIFont.labelFontSize)
let boldFont = UIFont.boldSystemFont(ofSize: UIFont.labelFontSize)

let bolded = prediction.attributedFullText.mutableCopy() as! NSMutableAttributedString
bolded.enumerateAttribute(kGMSAutocompleteMatchAttribute, in: NSMakeRange(0, bolded.length), options: []) {
  (value, range: NSRange, stop: UnsafeMutablePointer<ObjCBool>) -> Void in
    let font = (value == nil) ? regularFont : boldFont
    bolded.addAttribute(NSFontAttributeName, value: font, range: range)
}

label.attributedText = bolded
    

Objective-C

UIFont *regularFont = [UIFont systemFontOfSize:[UIFont labelFontSize]];
UIFont *boldFont = [UIFont boldSystemFontOfSize:[UIFont labelFontSize]];

NSMutableAttributedString *bolded = [prediction.attributedFullText mutableCopy];
[bolded enumerateAttribute:kGMSAutocompleteMatchAttribute
                   inRange:NSMakeRange(0, bolded.length)
                   options:0
                usingBlock:^(id value, NSRange range, BOOL *stop) {
                  UIFont *font = (value == nil) ? regularFont : boldFont;
                  [bolded addAttribute:NSFontAttributeName value:font range:range];
                }];

label.attributedText = bolded;
    

استخدام أداة الجلب

إذا أردت إنشاء عنصر تحكّم خاص بالإكمال التلقائي من البداية، يمكنك استخدام GMSAutocompleteFetcher، الذي يغلّف طريقة autocompleteQuery في GMSPlacesClient. يحدّ برنامج الجلب من عدد الطلبات، ولا يعرض سوى نتائج النص الذي تم إدخاله مؤخرًا. ولا يوفّر أي عناصر لواجهة المستخدم.

لتنفيذ GMSAutocompleteFetcher، اتّبِع الخطوات التالية:

  1. نفِّذ بروتوكول GMSAutocompleteFetcherDelegate
  2. أنشئ GMSAutocompleteFetcher عنصرًا.
  3. استدعِ الدالة sourceTextHasChanged في أداة الجلب أثناء كتابة المستخدم.
  4. التعامل مع التوقعات والأخطاء باستخدام طريقتَي البروتوكول didAutcompleteWithPredictions وdidFailAutocompleteWithError

يوضّح مثال الرمز البرمجي التالي كيفية استخدام أداة الجلب للحصول على إدخال المستخدم وعرض نتائج مطابقة الأماكن في عرض نصي. تم حذف وظيفة اختيار مكان. FetcherSampleViewController مشتق من UIViewController في FetcherSampleViewController.h.

Swift

import UIKit
import GooglePlaces

class ViewController: UIViewController {

  var textField: UITextField?
  var resultText: UITextView?
  var fetcher: GMSAutocompleteFetcher?

  override func viewDidLoad() {
    super.viewDidLoad()

    view.backgroundColor = .white
    edgesForExtendedLayout = []

    // Set bounds to inner-west Sydney Australia.
    let neBoundsCorner = CLLocationCoordinate2D(latitude: -33.843366,
                                                longitude: 151.134002)
    let swBoundsCorner = CLLocationCoordinate2D(latitude: -33.875725,
                                                longitude: 151.200349)

    // Set up the autocomplete filter.
    let filter = GMSAutocompleteFilter()
    filter.locationRestriction = GMSPlaceRectangularLocationOption(neBoundsCorner, swBoundsCorner)

    // Create a new session token.
    let token: GMSAutocompleteSessionToken = GMSAutocompleteSessionToken.init()

    // Create the fetcher.
    fetcher = GMSAutocompleteFetcher(bounds: nil, filter: filter)
    fetcher?.delegate = self
    fetcher?.provide(token)

    textField = UITextField(frame: CGRect(x: 5.0, y: 10.0,
                                          width: view.bounds.size.width - 5.0,
                                          height: 64.0))
    textField?.autoresizingMask = .flexibleWidth
    textField?.addTarget(self, action: #selector(textFieldDidChange(textField:)),
                         for: .editingChanged)
    let placeholder = NSAttributedString(string: "Type a query...")

    textField?.attributedPlaceholder = placeholder

    resultText = UITextView(frame: CGRect(x: 0, y: 65.0,
                                          width: view.bounds.size.width,
                                          height: view.bounds.size.height - 65.0))
    resultText?.backgroundColor = UIColor(white: 0.95, alpha: 1.0)
    resultText?.text = "No Results"
    resultText?.isEditable = false

    self.view.addSubview(textField!)
    self.view.addSubview(resultText!)
  }

  @objc func textFieldDidChange(textField: UITextField) {
    fetcher?.sourceTextHasChanged(textField.text!)
  }

}

extension ViewController: GMSAutocompleteFetcherDelegate {
  func didAutocomplete(with predictions: [GMSAutocompletePrediction]) {
    let resultsStr = NSMutableString()
    for prediction in predictions {
      resultsStr.appendFormat("\n Primary text: %@\n", prediction.attributedPrimaryText)
      resultsStr.appendFormat("Place ID: %@\n", prediction.placeID)
    }

    resultText?.text = resultsStr as String
  }

  func didFailAutocompleteWithError(_ error: Error) {
    resultText?.text = error.localizedDescription
  }
}

Objective-C

#import "FetcherSampleViewController.h"
#import <GooglePlaces/GooglePlaces.h>

@interface FetcherSampleViewController () <GMSAutocompleteFetcherDelegate>

@end

@implementation FetcherSampleViewController {
  UITextField *_textField;
  UITextView *_resultText;
  GMSAutocompleteFetcher* _fetcher;
}

-   (void)viewDidLoad {
  [super viewDidLoad];

  self.view.backgroundColor = [UIColor whiteColor];
  self.edgesForExtendedLayout = UIRectEdgeNone;

  // Set bounds to inner-west Sydney Australia.
  CLLocationCoordinate2D neBoundsCorner = CLLocationCoordinate2DMake(-33.843366, 151.134002);
  CLLocationCoordinate2D swBoundsCorner = CLLocationCoordinate2DMake(-33.875725, 151.200349);

  GMSAutocompleteFilter *autocompleteFilter = [[GMSAutocompleteFilter alloc] init];
  autocompleteFilter.locationRestriction =
        GMSPlaceRectangularLocationOption(neBoundsCorner, swBoundsCorner);

  // Create the fetcher.
  _fetcher = [[GMSAutocompleteFetcher alloc] initWithBounds:nil
                                                     filter:filter];
  _fetcher.delegate = self;

  // Set up the UITextField and UITextView.
  _textField = [[UITextField alloc] initWithFrame:CGRectMake(5.0f,
                                                             0,
                                                             self.view.bounds.size.width - 5.0f,
                                                             44.0f)];
  _textField.autoresizingMask = UIViewAutoresizingFlexibleWidth;
  [_textField addTarget:self
                 action:@selector(textFieldDidChange:)
       forControlEvents:UIControlEventEditingChanged];
  _resultText =[[UITextView alloc] initWithFrame:CGRectMake(0,
                                                            45.0f,
                                                            self.view.bounds.size.width,
                                                            self.view.bounds.size.height - 45.0f)];
  _resultText.backgroundColor = [UIColor colorWithWhite:0.95f alpha:1.0f];
  _resultText.text = @"No Results";
  _resultText.editable = NO;
  [self.view addSubview:_textField];
  [self.view addSubview:_resultText];
}

-   (void)textFieldDidChange:(UITextField *)textField {
  NSLog(@"%@", textField.text);
  [_fetcher sourceTextHasChanged:textField.text];
}

#pragma mark - GMSAutocompleteFetcherDelegate
-   (void)didAutocompleteWithPredictions:(NSArray *)predictions {
  NSMutableString *resultsStr = [NSMutableString string];
  for (GMSAutocompletePrediction *prediction in predictions) {
      [resultsStr appendFormat:@"%@\n", [prediction.attributedPrimaryText string]];
  }
  _resultText.text = resultsStr;
}

-   (void)didFailAutocompleteWithError:(NSError *)error {
  _resultText.text = [NSString stringWithFormat:@"%@", error.localizedDescription];
}

@end

رموز الجلسات المميزة

تجمّع رموز الجلسات مرحلتَي طلب البحث والاختيار في عملية البحث بالإكمال التلقائي التي يجريها المستخدم في جلسة منفصلة لأغراض الفوترة. تبدأ الجلسة عندما يبدأ المستخدم في كتابة طلب بحث، وتنتهي عندما يختار مكانًا. يمكن أن تتضمّن كل جلسة طلبات بحث متعدّدة، يليها اختيار مكان واحد. وبعد انتهاء الجلسة، لن يكون الرمز المميّز صالحًا، ويجب أن ينشئ تطبيقك رمزًا مميّزًا جديدًا لكل جلسة. ننصحك باستخدام رموز الجلسات المميزة لجميع جلسات الإكمال التلقائي الآلية (عند استخدام أداة التحكّم في ملء الشاشة أو أداة التحكّم في النتائج، تتولّى واجهة برمجة التطبيقات ذلك تلقائيًا).

تستخدِم حزمة تطوير البرامج Places SDK for iOS GMSAutocompleteSessionToken لتحديد كل جلسة. يجب أن يمرِّر تطبيقك رمزًا مميزًا جديدًا للجلسة عند بدء كل جلسة جديدة، ثم يمرِّر الرمز المميز نفسه، بالإضافة إلى معرّف المكان، في طلب fetchPlacefromPlaceID: اللاحق لاسترداد "تفاصيل المكان" للمكان الذي اختاره المستخدم.

مزيد من المعلومات حول الرموز المميزة للجلسات

استخدِم الرمز التالي لإنشاء رمز مميّز جديد للجلسة:

let token: GMSAutocompleteSessionToken = GMSAutocompleteSessionToken.init()

حدود الاستخدام

عرض بيانات تحديد المصدر في تطبيقك

  • إذا كان تطبيقك يستخدم خدمة الإكمال التلقائي آليًا، يجب أن تعرض واجهة المستخدم إشارة تحديد مصدر "مقدَّمة من Google" أو أن تظهر ضمن خريطة تحمل علامة Google التجارية.
  • إذا كان تطبيقك يستخدم عنصر التحكّم في واجهة المستخدم للإكمال التلقائي، لن تحتاج إلى اتّخاذ أي إجراء إضافي (يتم عرض بيان المصدر المطلوب تلقائيًا).
  • إذا استرجعت وعرضت معلومات إضافية عن المكان بعد الحصول على مكان حسب رقم التعريف، عليك عرض بيانات المصدر التابعة لجهات خارجية أيضًا.

لمزيد من التفاصيل، يُرجى الاطّلاع على المستندات المتعلقة بالمراجع.

التحكّم في مؤشر نشاط الشبكة

للتحكّم في مؤشر نشاط الشبكة في شريط حالة التطبيقات، عليك تنفيذ طرق التفويض الاختيارية المناسبة لفئة الإكمال التلقائي التي تستخدمها، وتفعيل مؤشر الشبكة وإيقافه بنفسك.

  • بالنسبة إلى GMSAutocompleteViewController، يجب تنفيذ طريقتَي التفويض didRequestAutocompletePredictions: وdidUpdateAutocompletePredictions:.
  • بالنسبة إلى GMSAutocompleteResultsViewController، عليك تنفيذ طريقتَي التفويض didRequestAutocompletePredictionsForResultsController: وdidUpdateAutocompletePredictionsForResultsController:.
  • بالنسبة إلى GMSAutocompleteTableDataSource، عليك تنفيذ طريقتَي التفويض didRequestAutocompletePredictionsForTableDataSource: وdidUpdateAutocompletePredictionsForTableDataSource:.

من خلال تنفيذ هذه الطرق وضبط [UIApplication sharedApplication].networkActivityIndicatorVisible على YES وNO على التوالي، سيتطابق شريط الحالة بشكل صحيح مع واجهة المستخدم الخاصة بالإكمال التلقائي.

تقييد نتائج الإكمال التلقائي

يمكنك ضبط عنصر التحكّم في واجهة مستخدم الإكمال التلقائي لحصر النتائج بمنطقة جغرافية معيّنة و/أو فلترة النتائج لتشمل نوعًا واحدًا أو أكثر من أنواع الأماكن أو بلدًا واحدًا أو أكثر. لتقييد النتائج، يمكنك إجراء ما يلي:

  • لتفضيل (تحيّز) النتائج ضمن المنطقة المحدّدة، اضبط locationBias على GMSAutocompleteFilter (قد يتم عرض بعض النتائج من خارج المنطقة المحدّدة). إذا تم ضبط locationRestriction أيضًا، سيتم تجاهل locationBias.
  • لعرض (حصر) النتائج ضمن المنطقة المحدّدة فقط، اضبط locationRestriction على GMSAutocompleteFilter (لن يتم عرض سوى النتائج ضمن المنطقة المحدّدة).

    • ملاحظة: لا يتم تطبيق هذا القيد إلا على المسارات الكاملة، وقد يتم عرض نتائج اصطناعية تقع خارج الحدود المستطيلة استنادًا إلى مسار يتداخل مع قيد الموقع الجغرافي.
  • لعرض النتائج التي تتوافق مع نوع مكان معيّن فقط، اضبط types على GMSAutocompleteFilter (على سبيل المثال، سيؤدي تحديد TypeFilter.ADDRESS إلى أن تعرض الأداة النتائج التي تتضمّن عنوانًا دقيقًا فقط).

  • لعرض النتائج من ما يصل إلى خمسة بلدان محدّدة فقط، اضبط قيمة countries على GMSAutocompleteFilter.

تحيز النتائج لمنطقة معيّنة

لتفضيل (تحيز) النتائج ضمن المنطقة المحدّدة، اضبط locationBias على GMSAutocompleteFilter، كما هو موضّح هنا:

northEast = CLLocationCoordinate2DMake(39.0, -95.0);  southWest =
CLLocationCoordinate2DMake(37.5, -100.0);  GMSAutocompleteFilter *filter =
[[GMSAutocompleteFilter alloc] init];  filter.locationBias =
GMSPlaceRectangularLocationOption(northEast, southWest);

حصر النتائج على منطقة معيّنة

لعرض النتائج (حصرها) ضمن المنطقة المحدّدة فقط، اضبط locationRestriction على GMSAutocompleteFilter، كما هو موضّح هنا:

northEast = CLLocationCoordinate2DMake(39.0, -95.0);  southWest =
CLLocationCoordinate2DMake(37.5, -100.0);  GMSAutocompleteFilter *filter =
[[GMSAutocompleteFilter alloc] init];  filter.locationRestriction =
GMSPlaceRectangularLocationOption(northEast, southWest);

فلترة النتائج حسب البلد

لفلترة النتائج ضمن ما يصل إلى خمسة بلدان محدّدة، اضبط countries على GMSAutocompleteFilter، كما هو موضّح هنا:

GMSAutocompleteFilter *filter = [[GMSAutocompleteFilter alloc] init];
filter.countries = @[ @"au", @"nz" ];

فلترة النتائج حسب نوع المكان أو مجموعة الأنواع

يمكن حصر النتائج بنوع معيّن أو مجموعة أنواع من خلال ضبط السمة types الخاصة بالعنصر GMSAutoCompleteFilter. استخدِم هذه السمة لتحديد الفلاتر المُدرَجة في الجداول 1 و2 و3 ضمن أنواع الأماكن. إذا لم يتم تحديد أي نوع، سيتم عرض جميع الأنواع.

لتحديد فلتر نوع أو مجموعة أنواع:

  • استخدِم السمة types لتحديد ما يصل إلى خمس قيم type من الجدول 1 والجدول 2 المعروضَين في أنواع الأماكن. يتم تحديد قيم النوع من خلال الثوابت في GMSPlaceType.

  • استخدِم السمة types لتحديد مجموعة أنواع من الجدول 3 المعروض في أنواع الأماكن. يتم تحديد قيم مجموعة الأنواع من خلال الثوابت في GMSPlaceType.

    يُسمح بنوع واحد فقط من الجدول 3 في الطلب. إذا حدّدت قيمة من الجدول 3، لا يمكنك تحديد قيمة من الجدول 1 أو الجدول 2. وفي حال حدوث ذلك، سيحدث خطأ.

على سبيل المثال، لعرض النتائج التي تتوافق مع نوع مكان معيّن فقط، اضبط types على GMSAutocompleteFilter. يوضّح المثال التالي كيفية ضبط الفلتر لعرض النتائج التي تتضمّن عنوانًا دقيقًا فقط:

GMSAutocompleteFilter *filter = [[GMSAutocompleteFilter alloc] init];
filter.types = @[ kGMSPlaceTypeAirport, kGMSPlaceTypeAmusementPark ];

تحسين خدمة "الإكمال التلقائي للأماكن" (الإصدار القديم)

يوضّح هذا القسم أفضل الممارسات لمساعدتك في الاستفادة إلى أقصى حدّ من خدمة Place Autocomplete (الإصدار القديم).

في ما يلي بعض الإرشادات العامة:

أفضل الممارسات لتحسين التكلفة

تحسين التكلفة الأساسية

لتحسين تكلفة استخدام خدمة Place Autocomplete (الإصدار القديم)، استخدِم أقنعة الحقول في أدوات Place Details (الإصدار القديم) وPlace Autocomplete (الإصدار القديم) لعرض حقول بيانات الأماكن التي تحتاج إليها فقط.

تحسين التكلفة بشكلٍ متقدّم

ننصحك بتنفيذ خدمة الإكمال التلقائي للأماكن (الإصدار القديم) آليًا للوصول إلى أسعار الطلب الواحد وطلب نتائج Geocoding API حول المكان المحدّد بدلاً من تفاصيل المكان (الإصدار القديم). يكون نموذج التسعير "حسب الطلب" مع Geocoding API أكثر فعالية من حيث التكلفة من نموذج التسعير "حسب الجلسة" (القائم على الجلسة) في حال استيفاء الشرطَين التاليَين:

  • إذا كنت تحتاج فقط إلى خطوط الطول والعرض أو عنوان المكان الذي اختاره المستخدم، تقدّم Geocoding API هذه المعلومات بتكلفة أقل من طلب Place Details (Legacy).
  • إذا اختار المستخدمون توقّعًا من ميزة "الإكمال التلقائي" في غضون أربعة طلبات أو أقل من طلبات ميزة "الإكمال التلقائي للأماكن" (الإصدار القديم)، قد يكون التسعير "لكل طلب" أكثر فعالية من حيث التكلفة من التسعير "لكل جلسة".
للمساعدة في اختيار عملية تنفيذ Place Autocomplete (الإصدار القديم) التي تناسب احتياجاتك، اختَر علامة التبويب التي تتوافق مع إجابتك عن السؤال التالي.

هل يتطلّب تطبيقك أي معلومات أخرى غير العنوان وخط العرض/خط الطول الخاص بالتوقّع المحدّد؟

نعم، يجب إضافة المزيد من التفاصيل

استخدام ميزة "الإكمال التلقائي للأماكن" المستندة إلى الجلسة (طريقة قديمة) مع ميزة "تفاصيل المكان" (طريقة قديمة)
بما أنّ تطبيقك يتطلّب تفاصيل المكان (الإصدار القديم)، مثل اسم المكان أو حالة النشاط التجاري أو ساعات العمل، يجب أن يستخدم تطبيقك لميزة "الإكمال التلقائي للأماكن" (الإصدار القديم) رمزًا مميّزًا للجلسة (برمجيًا أو مضمّنًا في أدوات JavaScript أو Android أو iOS). لكل جلسة بالإضافة إلى وحدات حفظ المخزون لبيانات "أماكن" السارية، وذلك استنادًا إلى حقول بيانات الأماكن التي تطلبها.1

تنفيذ الأداة
تتضمّن أدوات JavaScript أو Android أو iOS ميزة إدارة الجلسات تلقائيًا. ويشمل ذلك طلبات Place Autocomplete (الإصدار القديم) وطلبات Place Details (الإصدار القديم) بشأن عبارة البحث المقترَحة المحدّدة. احرص على تحديد المَعلمة fields لضمان طلب حقول بيانات المكان التي تحتاج إليها فقط.

التنفيذ الآلي
استخدِم رمزًا مميزًا للجلسة مع طلبات الإكمال التلقائي للأماكن (الإصدار القديم). عند طلب تفاصيل المكان (الإصدار القديم) حول التوقّع المحدّد، أدرِج المَعلمات التالية:

  1. رقم تعريف المكان من ردّ الإكمال التلقائي للأماكن (الإصدار القديم)
  2. رمز الجلسة المميز المستخدَم في طلب الإكمال التلقائي للأماكن (الإصدار القديم)
  3. المَعلمة fields التي تحدّد حقول بيانات المكان التي تحتاج إليها

لا، يجب توفير العنوان والموقع الجغرافي فقط

قد تكون Geocoding API خيارًا أكثر فعالية من حيث التكلفة لتطبيقك مقارنةً بخدمة "تفاصيل المكان" (الإصدار القديم)، وذلك استنادًا إلى أداء استخدامك لخدمة "الإكمال التلقائي للأماكن" (الإصدار القديم). تختلف كفاءة ميزة "الإكمال التلقائي للأماكن" (الإصدار القديم) لكل تطبيق حسب ما يدخله المستخدمون والمكان الذي يتم فيه استخدام التطبيق وما إذا تم تنفيذ أفضل الممارسات لتحسين الأداء.

للإجابة عن السؤال التالي، حلِّل عدد الأحرف التي يكتبها المستخدم في المتوسط قبل اختيار توقّع من Place Autocomplete (الإصدار القديم) في تطبيقك.

هل يختار المستخدمون توقّعًا من خدمة "الإكمال التلقائي للأماكن" (الإصدار القديم) في أربعة طلبات أو أقل في المتوسط؟

نعم

تنفيذ خدمة الإكمال التلقائي للأماكن (الإصدار القديم) آليًا بدون رموز مميّزة للجلسة واستدعاء Geocoding API بشأن توقّع المكان المحدّد
تقدّم Geocoding API العناوين وإحداثيات خطوط العرض/الطول. إنّ إجراء أربعة طلبات إكمال تلقائي للأماكن (إصدار قديم) - لكل طلب بالإضافة إلى طلب Geocoding API بشأن عبارة البحث المقترَحة عن المكان المحدّد أقل من تكلفة الإكمال التلقائي للأماكن (إصدار قديم) لكل جلسة.1

ننصحك باتّباع أفضل الممارسات المتعلّقة بالأداء لمساعدة المستخدمين في الحصول على التوقّع الذي يبحثون عنه بعدد أقل من الأحرف.

لا

استخدام ميزة "الإكمال التلقائي للأماكن" المستندة إلى الجلسة (طريقة قديمة) مع ميزة "تفاصيل المكان" (طريقة قديمة)
بما أنّ متوسط عدد الطلبات التي تتوقّع إرسالها قبل أن يختار المستخدم نتيجة بحث من Place Autocomplete (الإصدار القديم) يتجاوز تكلفة التسعير لكل جلسة، يجب أن يستخدم تطبيقك لخدمة Place Autocomplete (الإصدار القديم) رمزًا مميزًا للجلسة لكل من طلبات Place Autocomplete (الإصدار القديم) وطلبات Place Details (الإصدار القديم) المرتبطة لكل جلسة.1

تنفيذ الأداة
تتضمّن أدوات JavaScript أو Android أو iOS ميزة إدارة الجلسات تلقائيًا. ويشمل ذلك طلبات Place Autocomplete (الإصدار القديم) وطلبات Place Details (الإصدار القديم) بشأن عبارة البحث المقترَحة المحدّدة. احرص على تحديد المَعلمة fields لضمان طلب حقول البيانات الأساسية فقط.

التنفيذ الآلي
استخدِم رمزًا مميزًا للجلسة مع طلبات الإكمال التلقائي للأماكن (الإصدار القديم). عند طلب تفاصيل المكان (الإصدار القديم) حول التوقّع المحدّد، أدرِج المَعلمات التالية:

  1. رقم تعريف المكان من ردّ الإكمال التلقائي للأماكن (الإصدار القديم)
  2. رمز الجلسة المميز المستخدَم في طلب الإكمال التلقائي للأماكن (الإصدار القديم)
  3. المَعلمة fields التي تحدّد حقول البيانات الأساسية، مثل العنوان والشكل الهندسي

تأخير طلبات Place Autocomplete (الإصدار القديم)
يمكنك استخدام استراتيجيات، مثل تأخير طلب Place Autocomplete (الإصدار القديم) إلى أن يكتب المستخدم الأحرف الثلاثة أو الأربعة الأولى، لكي يقدّم تطبيقك عددًا أقل من الطلبات. على سبيل المثال، يعني تقديم طلبات إلى Place Autocomplete (الإصدار القديم) لكل حرف بعد أن يكتب المستخدم الحرف الثالث أنّه إذا كتب المستخدم سبعة أحرف ثم اختار نتيجة بحث مقترَحة قدّمت لها طلبًا واحدًا إلى Geocoding API، ستكون التكلفة الإجمالية هي 4 طلبات إلى Place Autocomplete (الإصدار القديم) + Geocoding.1

إذا كان تأخير الطلبات سيؤدي إلى خفض متوسط الطلبات الآلية إلى أقل من أربعة، يمكنك اتّباع الإرشادات المتعلّقة بتنفيذ ميزة "الإكمال التلقائي للأماكن" (الإصدار القديم) المتوافق مع Geocoding API. يُرجى العِلم أنّ تأخير الطلبات قد يراه المستخدم على أنّه تأخير، إذ قد يتوقّع رؤية نتائج البحث المقترَحة مع كل ضغطة مفتاح جديدة.

ننصحك باتّباع أفضل الممارسات المتعلّقة بالأداء لمساعدة المستخدمين في الحصول على التوقّع الذي يبحثون عنه بعدد أقل من الأحرف.


  1. للاطّلاع على التكاليف، يُرجى الرجوع إلى قوائم أسعار "منصة خرائط Google".

أفضل الممارسات لتحسين الأداء

توضّح الإرشادات التالية طرقًا لتحسين أداء خدمة Place Autocomplete (الإصدار القديم):

  • أضِف قيود البلدان وتفضيل الموقع الجغرافي و (بالنسبة إلى عمليات التنفيذ الآلية) إعدادات اللغة المفضّلة إلى عملية تنفيذ ميزة "الإكمال التلقائي للأماكن" (الإصدار القديم). لا حاجة إلى تحديد اللغة المفضّلة عند استخدام الأدوات لأنّها تستند إلى اللغة المفضّلة المحدّدة في متصفّح المستخدم أو جهازه الجوّال.
  • إذا كانت ميزة "الإكمال التلقائي للأماكن" (الإصدار القديم) مصحوبة بخريطة، يمكنك تحديد الموقع الجغرافي حسب إطار عرض الخريطة.
  • في الحالات التي لا يختار فيها المستخدم أحد التوقعات التي تقدّمها خدمة Place Autocomplete (الإصدار القديم)، وذلك بشكل عام لأنّ أيًا من هذه التوقعات ليس عنوان النتيجة المطلوب، يمكنك إعادة استخدام إدخال المستخدم الأصلي لمحاولة الحصول على نتائج أكثر صلة بالموضوع: تشمل السيناريوهات الأخرى التي يُنصح فيها بالرجوع إلى Geocoding API ما يلي:
    • المستخدمون الذين يدخلون عناوين أماكن فرعية، مثل عناوين وحدات أو شقق معيّنة داخل مبنى على سبيل المثال، يؤدي عنوان التشيك "Stroupežnického 3191/17, Praha" إلى ظهور عبارة بحث مقترَحة جزئية في ميزة "الإكمال التلقائي للأماكن" (الإصدار القديم).
    • المستخدمون الذين يدخلون عناوين تتضمّن بادئات مقاطع طرق، مثل "23-30 29th St, Queens" في مدينة نيويورك أو "47-380 Kamehameha Hwy, Kaneohe" في جزيرة كاواي في هاواي

تحديد المشاكل وحلّها

على الرغم من إمكانية حدوث مجموعة متنوعة من الأخطاء، فإنّ معظم الأخطاء التي من المحتمل أن يواجهها تطبيقك تحدث عادةً بسبب أخطاء في الإعداد (على سبيل المثال، تم استخدام مفتاح API غير صحيح، أو تم إعداد مفتاح API بشكل غير صحيح)، أو أخطاء في الحصة (تجاوز تطبيقك حصته). يمكنك الاطّلاع على حدود الاستخدام للحصول على مزيد من المعلومات حول الحصص.

يتم عرض الأخطاء التي تحدث عند استخدام عناصر التحكّم في الإكمال التلقائي في الطريقة didFailAutocompleteWithError() الخاصة ببروتوكولات التفويض المختلفة. تم ضبط السمة code الخاصة بالعنصر NSError المقدَّم على إحدى قيم التعداد GMSPlacesErrorCode.