地点自动补全

请选择平台: Android iOS JavaScript 网络服务

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:NSSelectorFromString(@"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
  2. 在父视图控制器中实现 GMSAutocompleteResultsViewControllerDelegate 协议,并将父视图控制器分配为委托属性。
  3. 创建一个 UISearchController 对象,传入 GMSAutocompleteResultsViewController 作为结果控制器参数。
  4. GMSAutocompleteResultsViewController 设置为 UISearchControllersearchResultsUpdater 属性。
  5. UISearchControllersearchBar 添加到应用的界面中。
  6. 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
  5. didAutocompleteWithPlace 委托方法中处理用户的选择。
  6. didAutocompleteWithPlacedidFailAutocompleteWithErrorwasCancelled 委托方法中关闭控制器。

以下代码示例演示了如何在单独添加 UISearchBar 时使用 GMSAutocompleteTableDataSource 类驱动 UIViewController 的表视图。

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,以检索用户所选地点的地点详情。
  • 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);
    }
  }
}];

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

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

  • attributedFullText - 预测的完整文本,格式为 NSAttributedString。例如,“Sydney Opera House, Sydney, New South Wales, Australia”。每个与用户输入匹配的文本范围都有一个 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>
#import <GoogleMapsBase/GoogleMapsBase.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(可能仍会返回所定义区域内的某些结果)。如果还设置了 locationRestriction,则 locationBias 将被忽略。
  • 如需仅显示(限制)指定区域内的结果,请在 GMSAutocompleteFilter 上设置 locationRestriction(系统将仅返回指定区域内的结果)。

    • 注意:此限制仅适用于整个路线,根据与位置限制重叠的路线,可能会返回位于矩形边界之外的合成结果。
  • 如需仅返回符合特定地点类型的结果,请为 GMSAutocompleteFilter 设置 types(例如,指定 TypeFilter.ADDRESS 将使 widget 仅返回具有精确地址的结果)。

  • 如需仅返回最多五个指定国家/地区的结果,请在 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);

按国家/地区过滤结果

如需过滤最多五个指定国家/地区的结果,请在 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 ];

地点自动补全优化

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

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

  • 若要开发可正常运行的界面,最快的方式是使用 Maps JavaScript API Autocomplete widget、Places SDK for Android Autocomplete widget 或 Places SDK for iOS Autocomplete 界面控件
  • 从一开始就了解重要的地点自动补全数据字段
  • 位置自定义调整和位置限制字段是可选的,但可能会对自动补全性能产生重大影响。
  • 使用错误处理可确保您的应用在 API 返回错误时妥善降级。
  • 请确保您的应用可以处理没有选择任何内容的情况,并能够让用户继续操作。

费用优化最佳实践

基本费用优化

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

高级费用优化

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

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

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

是,需要更多详细信息

将基于会话的地点自动补全与地点详情搭配使用
由于您的应用需要地点名称、商家状态或营业时间等地点详情,因此您的地点自动补全实现应使用会话令牌(以程序化方式构建,或内置到 JavaScriptAndroidiOS widget 中),总费用为每次会话 0.017 美元,外加相应的地点数据 SKU 费用(具体取决于您申请的地点数据字段)。1

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

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

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

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

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

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

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

在不使用会话令牌的情况下以程序化方式实现地点自动补全,并针对所选的地点预测调用 Geocoding API。
Geocoding API 提供地址和纬度/经度坐标,价格为每个请求 0.005 美元。发出四次地点自动补全 - 按请求结算请求的费用为 0.01132 美元,因此四次请求加上针对所选地点预测调用 Geocoding API 的总费用将为 0.01632 美元,低于按会话结算的自动补全价格(即每次会话 0.017 美元)。1

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

将基于会话的地点自动补全与地点详情搭配使用
由于您预计在用户选择地点自动补全预测结果之前应用发出的平均请求次数较多,所需费用会超过“按会话”定价模式的费用,因此建议您在实现地点自动补全时,针对“地点自动补全”请求和关联的“地点详情”请求使用会话令牌,总费用为每次会话 0.017 美元。1

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

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

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

考虑延迟“地点自动补全”请求
您可以采取一些策略,例如延迟“地点自动补全”请求,直到用户输入前三个或四个字符,从而减少应用发出的请求数量。例如,在用户输入第三个字符后针对每个字符发出“地点自动补全”请求,也就是说,如果用户输入七个字符,然后选择了您发出一次 Geocoding API 请求所获得的预测结果,总费用将为:0.01632 美元(4 * 0.00283 美元 [自动补全 - 按请求结算] + 0.005 美元 [地理编码])。1

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

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


  1. 此处所列的费用以美元为单位。如需了解完整的定价信息,请参阅 Google Maps Platform 结算页面。

性能最佳实践

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

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

问题排查

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

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