地点自动补全

Places SDK for iOS 中的自动补全服务会针对用户搜索查询返回地点预测结果。在用户输入内容时,自动补全服务会返回地点建议,例如商家、地址、plus code 和地图注点。

您可以通过以下方式向应用中添加自动填充服务:

添加自动补全界面控件

自动补全界面控件是一个内置自动补全功能的搜索对话框。当用户输入搜索字词时,该控件会显示一个预测地点列表供用户选择。当用户做出选择后,系统会返回一个 GMSPlace 实例,您的应用随后可以使用该实例获取所选地点的详细信息。

您可以使用以下方式将自动填充 UI 控件添加到应用中:

添加全屏控件

如果您需要模态上下文,即自动补全界面暂时替换应用界面,直到用户做出选择,请使用全屏控件。此功能由 GMSAutocompleteViewController 类提供。当用户选择一个地点后,您的应用会收到回调。

要向应用中添加全屏控件,请执行以下操作:

  1. 在主应用中创建一个界面元素,以启动自动补全界面控件,例如 UIButton 上的触摸事件处理程序。
  2. 在父视图控制器中实现 GMSAutocompleteViewControllerDelegate 协议。
  3. 创建 GMSAutocompleteViewController 的实例,并将父视图控制器分配为委托属性。
  4. 创建 GMSPlaceField 以定义要返回的地点数据类型。
  5. 添加 GMSAutocompleteFilter 以将查询限制为特定类型的地点
  6. 使用 [self presentViewController...] 呈现 GMSAutocompleteViewController
  7. didAutocompleteWithPlace 委托方法中处理用户的选择。
  8. didAutocompleteWithPlacedidFailAutocompleteWithErrorwasCancelled 委托方法中关闭控制器。

以下示例演示了一种用于启动 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 设置为 UISearchControllersearchResultsUpdater 属性。
  4. UISearchControllersearchBar 添加到应用的界面中。
  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. 在视图控制器中实现 GMSAutocompleteTableDataSourceDelegateUISearchBarDelegate 协议。
  2. 创建一个 GMSAutocompleteTableDataSource 实例,并将视图控制器分配为委托属性。
  3. GMSAutocompleteTableDataSource 设置为视图控制器上 UITableView 实例的数据源和委托属性。
  4. 在搜索文本输入的处理脚本中,对 GMSAutocompleteTableDataSource 调用 sourceTextHasChanged
    1. didAutocompleteWithPlace 委托方法中处理用户的选择。
  5. didAutocompleteWithPlacedidFailAutocompleteWithErrorwasCancelled 委托方法中关闭控制器。

以下代码示例演示了如何使用 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

      

自定义文本和背景颜色

您可以设置自动完成界面控件中所有文本和背景的颜色,使 widget 与应用的视觉外观更加一致。设置 UI 控件颜色的方式有以下两种:

  • 尽可能使用内置的 iOS UIAppearance 协议来全局设置界面控件的样式。这些设置适用于许多(但不是全部)界面控制元素。
  • 通过使用 widget 类中的 SDK 方法来设置 UIAppearance 协议不支持的属性。

通常,您的应用会结合使用 UIAppearance 协议和 SDK 方法。下图显示可以设置样式的元素:

自动补全界面控件颜色

下表列出了所有界面元素,并指明了应如何设置每个元素的样式(通过 UIAppearance 协议或 SDK 方法)。

界面元素 方法 造型百科
导航栏着色(背景) UIAppearance 协议 UINavigationBar 代理上调用 setBarTintColor
导航栏着色颜色(搜索栏文本光标和“取消”按钮) UIAppearance 协议 UINavigationBar 代理上调用 setTintColor
搜索栏文字颜色 UIAppearance 协议 searchBarTextAttributes 中设置 NSForegroundColorAttributeName
搜索栏着色颜色 不适用 搜索栏是半透明的,将显示为导航栏的阴影版本。
搜索栏占位符文本颜色(默认搜索文本) UIAppearance 协议 placeholderAttributes 中设置 NSForegroundColorAttributeName
主要文本(也适用于错误和消息文本) SDK 方法 欢迎致电primaryTextColor
主要文本突出显示 SDK 方法 欢迎致电primaryTextHighlightColor
辅助文本 SDK 方法 欢迎致电secondaryTextColor
错误和消息文本 SDK 方法 欢迎致电primaryTextColor
表格单元格背景 SDK 方法 欢迎致电tableCellBackgroundColor
表格单元格分隔线颜色 SDK 方法 欢迎致电tableCellSeparatorColor
“重试”按钮 SDK 方法 欢迎致电tintColor
活动指示器(进度微调器) UIAppearance 协议 UIActivityIndicatorView 代理上调用 setColor
“Powered by Google”徽标,悲伤的云图片 不适用 系统会根据背景对比度自动选择白色或灰色版本。
搜索栏文本字段中的放大镜和清除文字图标 不适用 如需设置样式,请将默认图片替换为所需颜色的图片。

使用 UIAppearance 协议

您可以使用 UIAppearance 协议来获取给定界面元素的外观代理,然后使用该代理来设置界面元素的颜色。进行修改时,指定界面元素的所有实例都会受到影响。例如,以下示例会在 UITextField 类包含在 UISearchBar 中时,将其文本颜色全局更改为绿色:

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

如需详细了解如何定义颜色值,请参阅 UIColor 类参考

以下代码段显示了您需要使用的所有代理命令,以便为全屏自动补全界面控件中的所有内容设置样式。将以下代码添加到 Appdelegate.m 中的 didFinishLaunchingWithOptions 方法:

// 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 的界面控件实例。将以下代码添加到 ViewController.m 中的 onLaunchClicked 方法中:

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;

以编程方式获取地点预测结果

您可以创建自定义搜索界面,以替代自动补全 widget 提供的界面。为此,您的应用必须以编程方式获取地点预测结果。您的应用可以通过以下方式之一获取预测地点名称和/或地址的列表:

正在呼叫GMSPlacesClient findAutocompletePredictionsFromQuery:

如需获取预测的地点名称和/或地址列表,请先实例化 GMSPlacesClient,然后使用以下参数调用 GMSPlacesClient findAutocompletePredictionsFromQuery: 方法:

  • 一个 autocompleteQuery 字符串,包含用户输入的文字。
  • 一个 GMSAutocompleteSessionToken,用于标识每个会话。您的应用应为每个自动补全请求调用传递同一令牌,然后在后续对 fetchPlacefromPlaceID: 的调用中传递该令牌以及地点 ID,以检索用户所选地点的地点详情。
  • A GMSAutocompleteFilter 至:
    • 使结果偏向于特定区域或将结果限制在特定区域内。
    • 将结果限制为特定类型的地点
    • 一个 GMSPlaceLocationBias/限制对象,用于使结果偏向由纬度和经度范围指定的特定区域。
  • 用于处理返回的预测结果的回调方法。

以下代码示例展示了对 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);
    }
  }
}];

该 API 会调用指定的回调方法,并传入一个 GMSAutocompletePrediction 对象数组。

每个 GMSAutocompletePrediction 对象都包含以下信息:

  • attributedFullText - 预测的完整文本,以 NSAttributedString 的形式呈现。例如,“悉尼歌剧院,悉尼,新南威尔士州,澳大利亚”。与用户输入匹配的每个文本范围都具有属性 kGMSAutocompleteMatchAttribute。您可以使用此属性突出显示用户查询中的匹配文本,例如,如下所示。
  • placeID - 预测地点的地点 ID。地点 ID 是唯一标识地点的文本标识符。如需详细了解地点 ID,请参阅地点 ID 概览
  • 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,它封装了 GMSPlacesClient 上的 autocompleteQuery 方法。提取器会限制请求,仅返回最近输入的搜索文本的结果。它不提供 UI 元素。

如需实现 GMSAutocompleteFetcher,请按以下步骤操作:

  1. 实现 GMSAutocompleteFetcherDelegate 协议。
  2. 创建一个 GMSAutocompleteFetcher 对象。
  3. 在用户输入内容时,对提取器调用 sourceTextHasChanged
  4. 使用 didAutcompleteWithPredictionsdidFailAutocompleteWithError 协议方法处理预测和错误。

以下代码示例演示了如何使用提取器来获取用户输入,并在文本视图中显示地点匹配结果。省略了选择地点的功能。FetcherSampleViewController 派生自 FetcherSampleViewController.h 中的 UIViewController

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

会话令牌

会话令牌将用户自动补全搜索的查询和选择阶段归入不同的会话,以便进行结算。会话在用户开始输入查询内容时开始,并在用户选择地点时结束。在每个会话中,用户可以输入多项查询内容,并最终选择一个地点。会话结束后,令牌将失效;您的应用必须为每个会话生成一个新的令牌。我们建议您针对所有程序化自动补全会话使用会话令牌(当您使用全屏控制器或结果控制器时,API 会自动处理此问题)。

Places SDK for iOS 使用 GMSAutocompleteSessionToken 来标识每个会话。您的应用应在每次新会话开始时传递新的会话令牌,然后在后续对 fetchPlacefromPlaceID: 的调用中传递该令牌以及地点 ID,以检索用户所选地点的地点详情。

详细了解会话令牌

使用以下代码生成新的会话令牌:

let token: GMSAutocompleteSessionToken = GMSAutocompleteSessionToken.init()

用量限额

在应用中显示提供方信息

  • 如果您的应用以编程方式使用自动补全服务,则界面必须显示“Powered by Google”提供方信息,或者显示在带有 Google 品牌的地图中。
  • 如果您的应用使用自动补全界面控件,则无需采取任何其他行动(系统默认会显示所需的提供方信息)。
  • 如果您在按 ID 获取地点后检索并显示其他地点信息,则还必须显示第三方提供方信息。

如需了解详情,请参阅有关提供方信息的文档。

控制网络活动指示器

如需控制应用状态栏中的网络活动指示器,您必须为所用的自动补全类实现相应的可选委托方法,并自行开启和关闭网络指示器。

  • 对于 GMSAutocompleteViewController,您必须实现委托方法 didRequestAutocompletePredictions:didUpdateAutocompletePredictions:
  • 对于 GMSAutocompleteResultsViewController,您必须实现委托方法 didRequestAutocompletePredictionsForResultsController:didUpdateAutocompletePredictionsForResultsController:
  • 对于 GMSAutocompleteTableDataSource,您必须实现委托方法 didRequestAutocompletePredictionsForTableDataSource:didUpdateAutocompletePredictionsForTableDataSource:

通过实现这些方法并将 [UIApplication sharedApplication].networkActivityIndicatorVisible 分别设置为 YESNO,状态栏将与自动完成界面正确匹配。

限制自动补全结果

您可以设置自动补全界面控件,将结果限制在特定地理区域,并/或将结果过滤为一种或多种地点类型,或过滤为特定国家/地区。如需限制结果,您可以执行以下操作:

  • 如需优先(自定义调整)显示指定区域内的结果,请将 GMSAutocompleteFilter 上的 locationBias 设置为 true(系统可能仍会返回指定区域以外的部分结果)。如果还设置了 locationRestriction,则会忽略 locationBias
  • 如需仅显示(限制)指定区域内的结果,请在 GMSAutocompleteFilter 上设置 locationRestriction(系统将仅返回指定区域内的结果)。

    • 注意:此限制仅会应用于整个路线,系统可能会根据与位置限制重叠的路线返回矩形边界范围以外的综合结果。
  • 如需仅返回符合特定地点类型的结果,请在 GMSAutocompleteFilter 上设置 types(例如,指定 TypeFilter.ADDRESS 将导致微件仅返回具有精确地址的结果)。

  • 如需仅返回最多五个指定国家/地区内的结果,请在 GMSAutocompleteFilter 上设置 countries

使结果偏向于特定区域

如需优先(倾向于)返回定义区域内的结果,请在 GMSAutocompleteFilter 上设置 locationBias,如下所示:

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

将结果限制在特定区域

如需仅显示(限制)指定区域内的结果,请在 GMSAutocompleteFilter 上设置 locationRestriction,如下所示:

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

按国家/地区过滤结果

如需过滤最多 5 个指定国家/地区内的结果,请在 GMSAutocompleteFilter 上设置 countries,如下所示:

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

按地点类型或类型集合过滤结果

通过设置 GMSAutoCompleteFiltertypes 属性,将结果限制为特定类型或类型集合。 使用此属性可指定地点类型中表 1、2 和 3 列出的过滤条件。若未指定任何类型,系统将返回所有类型。

如需指定类型或类型集合过滤条件,请执行以下操作:

  • 使用 types 属性指定地点类型中显示的表 1 和表 2 中的最多五个 type 值。类型值由 GMSPlaceType 中的常量定义。

  • 使用 types 属性指定地点类型中表 3 所示的类型集合。类型集合值由 GMSPlaceType 中的常量定义。

    只能在请求中使用表 3 中的一种类型。如果您指定了表 3 中的值,则无法指定表 1 或表 2 中的值。如果这样做,则会发生错误。

例如,如需仅返回符合特定地点类型的结果,请在 GMSAutocompleteFilter 上设置 types。以下示例展示了如何设置过滤器以仅返回具有精确地址的结果:

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

地点自动补全(旧版)优化

本部分介绍了帮助您充分利用地点自动补全(旧版)服务的最佳实践。

下面列出了一些一般准则:

费用优化最佳实践

基本费用优化

为了优化地点自动补全(旧版)服务的使用费用,请在地点详情(旧版)和地点自动补全(旧版)widget 中使用字段掩码,以便仅返回所需的地点数据字段

高级费用优化

请考虑通过程序化方式实现地点自动补全(旧版),以便采用“按请求”定价模式,并请求关于所选地点(而不是地点详情 [旧版])的 Geocoding API 结果。如果同时满足以下两个条件,与采用“按会话”(基于会话)定价模式相比,将“按请求”定价模式与 Geocoding API 搭配使用的性价比更高:

  • 如果您只需要用户所选地点的纬度/经度或地址,那么采用 Geocoding API 提供此类信息所需的费用会低于调用地点详情(旧版)。
  • 如果用户平均在不超过四次地点自动补全(旧版)预测请求之内选择自动补全预测结果,那么“按请求”定价模式可能会比“按会话”定价模式的性价比更高。
如果在选择符合您需求的地点自动补全(旧版)实现方面需要帮助,请选择与以下问题的答案相对应的标签页。

除了所选预测结果的地址和纬度/经度外,您的应用是否需要任何其他信息?

是,需要更多详细信息

将基于会话的地点自动补全(旧版)与地点详情(旧版)搭配使用。
由于您的应用需要地点详情(旧版),例如地点名称、营业状态或营业时间,因此您在实现地点自动补全(旧版)时应使用会话令牌(以编程方式或内置于 JavaScriptAndroidiOS widget 中)。按会话结算,外加适用的地点数据 SKU,具体取决于您请求的地点数据字段。1

widget 实现
会话管理功能自动内置于 JavaScriptAndroidiOS widget 中。这包括针对所选预测结果的“地点自动补全(旧版)”请求和“地点详情(旧版)”请求。请务必指定 fields 参数,以确保您只请求所需的地点数据字段

程序化实现
在“地点自动补全(旧版)”请求中使用会话令牌。在请求关于所选预测结果的地点详情(旧版)时,添加以下参数:

  1. “地点自动补全(旧版)”响应中的地点 ID
  2. “地点自动补全(旧版)”请求中使用的会话令牌
  3. fields 参数,用于指定您所需的地点数据字段

否,只需要地址和位置信息

对于您的应用,Geocoding API 可能比地点详情(旧版)性价比更高,具体取决于您使用地点自动补全(旧版)的性能。每个应用的地点自动补全(旧版)效率各有不同,具体取决于用户输入的内容、使用应用所在的位置,以及是否遵循了性能优化最佳实践

为了回答以下问题,请分析用户在您的应用中选择地点自动补全(旧版)预测结果之前平均会输入多少个字符。

平均而言,用户是否能够在不超过四次请求之内选择地点自动补全(旧版)预测结果?

在不使用会话令牌的情况下以程序化方式实现地点自动补全(旧版),并针对所选的地点预测调用 Geocoding API。
Geocoding API 提供地址和纬度/经度坐标。发出四次地点自动补全(旧版)- 按请求结算请求加上针对所选地点预测调用 Geocoding API 的费用低于按会话结算的地点自动补全(旧版)费用(每次会话)。1

您可以考虑采用性能最佳实践,帮助用户以更少的字符找到所需的预测结果。

将基于会话的地点自动补全(旧版)与地点详情(旧版)搭配使用。
由于您预计在用户选择地点自动补全(旧版)预测结果之前发出的请求的平均数量超过了按会话结算的价格,因此您在实现地点自动补全(旧版)时,应为地点自动补全(旧版)请求和关联的地点详情(旧版)请求使用会话令牌,每个会话使用一个。1

widget 实现
会话管理功能自动内置于 JavaScriptAndroidiOS widget 中。这包括针对所选预测结果的“地点自动补全(旧版)”请求和“地点详情(旧版)”请求。请务必指定 fields 参数,以确保您只请求基本数据字段。

程序化实现
在“地点自动补全(旧版)”请求中使用会话令牌。在请求关于所选预测结果的地点详情(旧版)时,添加以下参数:

  1. “地点自动补全(旧版)”响应中的地点 ID
  2. “地点自动补全(旧版)”请求中使用的会话令牌
  3. fields 参数,用于指定地址和几何图形等基本数据字段

考虑延迟“地点自动补全(旧版)”请求
您可以采取一些策略,例如延迟“地点自动补全(旧版)”请求,直到用户输入前三个或四个字符,从而减少应用发出的请求数量。例如,在用户输入第三个字符,针对每个字符发出地点自动补全(旧版)请求,这意味着如果用户输入七个字符,然后选择一个预测结果,而您针对该预测结果发出一个 Geocoding API 请求,则总费用将为 4 次地点自动补全(旧版)按请求结算的费用 + Geocoding 费用。1

如果延迟请求会导致平均程序化请求次数低于四次,您可以按照使用 Geocoding API 提高地点自动补全(旧版)性能的实现指南操作。请注意,如果用户希望每次输入新的字符后都能看到预测结果,可能会将延迟请求视为时间上的延迟。

您可以考虑采用性能最佳实践,帮助用户以较少的字符找到所需的预测结果。


  1. 如需了解费用,请参阅 Google Maps Platform 价格表

性能最佳实践

下面的指南介绍了优化地点自动补全(旧版)性能的方式:

  • 向地点自动补全(旧版)实现添加国家/地区限制、位置自定义调整和语言偏好设置(适用于程序化实现)。您无需为 widget 进行语言偏好设置,因为它们会从用户的浏览器或移动设备中选择语言偏好设置。
  • 如果地点自动补全(旧版)附有地图,您可以根据地图视口来设置位置偏向。
  • 如果用户未选择任一地点自动补全(旧版)预测结果,通常是因为这些预测结果都不是所需的结果地址,您可以重复使用原始用户输入来尝试获取更相关的结果: 适合回退到 Geocoding API 的其他场景包括:
    • 输入子地址的用户,例如建筑物内特定单元或公寓的地址。例如,捷克地址“Stroupežnického 3191/17, Praha”会在地点自动补全(旧版)中生成部分预测结果。
    • 用户在输入地址时,需要输入路段前缀,例如纽约的“23-30 29th St, Queens”或夏威夷考爱岛“47-380 Kamehameha Hwy, Kaneohe”。

问题排查

虽然可能会出现各种各样的错误,但您的应用最有可能遇到的错误通常是由配置错误(例如,使用了错误的 API 密钥或 API 密钥配置不正确)或配额错误(您的应用已超出其配额)引起的。如需详细了解配额,请参阅使用量限制

使用自动补全控件时发生的错误会在各种委托协议的 didFailAutocompleteWithError() 方法中返回。所提供的 NSError 对象的 code 属性设置为 GMSPlacesErrorCode 枚举的某个值。