您已全部設定完成!

若要開始開發,請參閱我們的開發人員文件

啟用 Google Places API for iOS

為協助您開始,我們將先引導您使用「Google 開發人員控制台」來執行一些動作:

  1. 建立或選擇專案
  2. 啟用 Google Places API for iOS
  3. 建立適當的金鑰
繼續

地點自動完成

Google Places API for iOS 中的自動完成服務會傳回地點預測來回應使用者搜尋查詢。 依照使用者類型,自動完成服務會傳回商家、地址和搜尋點之類的地點建議。

您可以用下列方式將自動完成新增至您的應用程式:

新增自動完成 UI 控制項

自動完成 UI 控制項是一個具備內建自動完成功能的搜尋對話方塊。 當使用者輸入搜尋字詞時,該控制項會出現一個預測的地點清單,供使用者從中選擇。 當使用者選取之後,就會傳回一個 GMSPlace 實例,然後,您的應用程式可以使用此實例來取得所選地點的詳細資料。

您可以用下列方式將自動完成 UI 控制項新增到您的應用程式:

新增全螢幕控制項

當您需要強制內容時,可使用全螢幕控制項,其中,自動完成 UI 會暫時取代您應用程式的 UI,直到使用者進行選取為止。 此功能是由 GMSAutocompleteViewController 類別所提供。 當使用者選取地點時,您的應用程式會收到回呼。

若要新增全螢幕控制項到您的應用程式:

  1. 在您的主要應用程式中建立 UI 元素,以啟動自動完成 UI,例如 UIButton 上的觸控處理常式。
  2. 在父項檢視控制器中實作 GMSAutocompleteViewControllerDelegate 通訊協定。
  3. 建立 GMSAutocompleteViewController 的實例,並將父項檢視控制器指派為委派屬性。
  4. 使用 [self presentViewController...] 來呈現 GMSAutocompleteViewController
  5. 處理使用者在 didAutocompleteWithPlace 委派方法中的選取。
  6. 關閉 didAutocompleteWithPlacedidFailAutocompleteWithErrorwasCancelled 委派方法中的控制器。

下列範例示範啟動 GMSAutocompleteViewController 以回應使用者輕按按鈕的其中一種可能方式。

Swift

import UIKit
import GooglePlaces

class ViewController: UIViewController {

  // Present the Autocomplete view controller when the button is pressed.
  @IBAction func autocompleteClicked(_ sender: UIButton) {
    let autocompleteController = GMSAutocompleteViewController()
    autocompleteController.delegate = self
    present(autocompleteController, animated: true, completion: nil)
  }
}

extension ViewController: GMSAutocompleteViewControllerDelegate {

  // Handle the user's selection.
  func viewController(_ viewController: GMSAutocompleteViewController, didAutocompleteWith place: GMSPlace) {
    print("Place name: \(place.name)")
    print("Place address: \(place.formattedAddress)")
    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/GooglePlaces.h>

@interface ViewController () <GMSAutocompleteViewControllerDelegate>

@end

@implementation ViewController

...

// Present the autocomplete view controller when the button is pressed.
- (IBAction)onLaunchClicked:(id)sender {
  GMSAutocompleteViewController *acController = [[GMSAutocompleteViewController alloc] init];
  acController.delegate = self;
  [self presentViewController:acController animated:YES completion:nil];
}

// 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 address %@", place.formattedAddress);
  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

新增結果控制器

當您想要對文字輸入 UI 有更多控制時,可使用結果控制器。 結果控制器會依據輸入 UI 焦點動態切換結果清單的能見度。

若要新增結果控制器到您的應用程式:

  1. 建立 GMSAutocompleteResultsViewController
  2. 在父項檢視控制器中實作 GMSAutocompleteResultsViewControllerDelegate 通訊協定,並將父項檢視控制器指派為委派屬性。
  3. 建立 UISearchController 物件,在 GMSAutocompleteResultsViewController 中傳遞做為結果控制器引數。
  4. GMSAutocompleteResultsViewController 設定為 UISearchControllersearchResultsUpdater 屬性。
  5. 新增 UISearchControllersearchBar 到您應用程式的 UI。
  6. 處理使用者在 didAutocompleteWithPlace 委派方法中的選取。

UISearchController 的搜尋列放進您應用程式 UI 的方式有以下幾種:

新增搜尋列至導覽列

下列程式碼範例示範新增結果控制器、新增 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;
}

注意:為了正確顯示搜尋列,您應用程式的檢視控制器必須包含在 UINavigationController 中。

新增搜尋列至視圖頂端

下列程式碼範例顯示新增 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;
}

注意:為了正確顯示搜尋列,您應用程式的檢視控制器必須包含在 UINavigationController 中。

使用表格資料來源

如果您的應用程式支援 iOS 7,可以使用 GMSAutocompleteTableDataSource 類別來促成 UISearchDisplayController 的表格檢視。

若要使用 GMSAutocompleteTableDataSource 來顯示搜尋控制器:

  1. 在父項檢視控制器中實作 GMSAutocompleteTableDataSourceDelegateUISearchDisplayDelegate 通訊協定。
  2. 建立 GMSAutocompleteTableDataSource 實例,並將父項檢視控制器指派為委派屬性。
  3. 建立 UISearchDisplayController 的實例。
  4. 新增 UISearchControllersearchBar 到您應用程式的 UI。
  5. 處理使用者在 didAutocompleteWithPlace 委派方法中的選取。
  6. 關閉 didAutocompleteWithPlacedidFailAutocompleteWithErrorwasCancelled 委派方法中的控制器。

下列程式碼範例示範使用 GMSAutocompleteTableDataSource 類別來促成 UISearchDisplayController 的表格檢視。

Swift

import UIKit
import GooglePlaces

class ViewController: UIViewController, UISearchDisplayDelegate {

  var searchBar: UISearchBar?
  var tableDataSource: GMSAutocompleteTableDataSource?
  var searchDisplayController: UISearchDisplayController?

  override func viewDidLoad() {
    super.viewDidLoad()

    searchBar = UISearchBar(CGRect(x: 0, y: 0, width: 250.0, height: 44.0))

    tableDataSource = GMSAutocompleteTableDataSource()
    tableDataSource?.delegate = self

    searchDisplayController = UISearchDisplayController(searchBar: searchBar!, contentsController: self)
    searchDisplayController?.searchResultsDataSource = tableDataSource
    searchDisplayController?.searchResultsDelegate = tableDataSource
    searchDisplayController?.delegate = self

    view.addSubview(searchBar!)
  }

  func didUpdateAutocompletePredictionsForTableDataSource(tableDataSource: GMSAutocompleteTableDataSource) {
    // Turn the network activity indicator off.
    UIApplication.sharedApplication().networkActivityIndicatorVisible = false
    // Reload table data.
    searchDisplayController?.searchResultsTableView.reloadData()
  }

  func didRequestAutocompletePredictionsForTableDataSource(tableDataSource: GMSAutocompleteTableDataSource) {
    // Turn the network activity indicator on.
    UIApplication.sharedApplication().networkActivityIndicatorVisible = true
    // Reload table data.
    searchDisplayController?.searchResultsTableView.reloadData()
  }

}

extension ViewController: GMSAutocompleteTableDataSourceDelegate {
  func tableDataSource(tableDataSource: GMSAutocompleteTableDataSource, didAutocompleteWithPlace place: GMSPlace) {
    searchDisplayController?.active = false
    // Do something with the selected place.
    print("Place name: \(place.name)")
    print("Place address: \(place.formattedAddress)")
    print("Place attributions: \(place.attributions)")
  }

  func searchDisplayController(controller: UISearchDisplayController, shouldReloadTableForSearchString searchString: String?) -> Bool {
    tableDataSource?.sourceTextHasChanged(searchString)
    return false
  }

  func tableDataSource(tableDataSource: GMSAutocompleteTableDataSource, didFailAutocompleteWithError error: NSError) {
    // TODO: Handle the error.
    print("Error: \(error.description)")
  }

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

Objective-C

- (void)viewDidLoad {
  [super viewDidLoad];
  // Do any additional setup after loading the view, typically from a nib.

  _searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0, 20, 250.0f, 44.0f)];

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

  _searchDisplayController = [[UISearchDisplayController alloc] initWithSearchBar:_searchBar
                                                               contentsController:self];
  _searchDisplayController.searchResultsDataSource = _tableDataSource;
  _searchDisplayController.searchResultsDelegate = _tableDataSource;
  _searchDisplayController.delegate = self;

  [self.view addSubview:_searchBar];
}

- (BOOL)searchDisplayController:(UISearchDisplayController *)controller
shouldReloadTableForSearchString:(NSString *)searchString
{
  [_tableDataSource sourceTextHasChanged:searchString];
  return NO;
}

// Handle the user's selection.
- (void)tableDataSource:(GMSAutocompleteTableDataSource *)tableDataSource
  didAutocompleteWithPlace:(GMSPlace *)place {
  [_searchDisplayController setActive:NO animated:YES];
  // Do something with the selected place.
  NSLog(@"Place name %@", place.name);
  NSLog(@"Place address %@", place.formattedAddress);
  NSLog(@"Place attributions %@", place.attributions.string);
}

- (void)tableDataSource:(GMSAutocompleteTableDataSource *)tableDataSource
  didFailAutocompleteWithError:(NSError *)error {
  [_searchDisplayController setActive:NO animated:YES];
  // TODO: handle the error.
  NSLog(@"Error: %@", [error description]);
}

- (void)didUpdateAutocompletePredictionsForTableDataSource:
  (GMSAutocompleteTableDataSource *)tableDataSource {
  // Turn the network activity indicator off.
  [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
  // Reload table data.
  [_searchDisplayController.searchResultsTableView reloadData];
}

- (void)didRequestAutocompletePredictionsForTableDataSource:
  (GMSAutocompleteTableDataSource *)tableDataSource {
  // Turn the network activity indicator on.
  [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
  // Reload table data.
  [_searchDisplayController.searchResultsTableView reloadData];
}

注意:UISearchDisplayController API 不支援非同步資料更新的概念,因此必須在 GMSAutoCompleteResultsDelegate 通訊協定的 didUpdateAutocompletePredictionsdidRequestAutocompletePredictions 方法中重新載入表格資料,來強制表格更新。

自訂文字與背景色彩

您可以設定自動完成 UI 控制器中所有文字與背景的色彩,讓小工具與您應用程式的視覺外觀更為搭配。 設定 UI 控制器色彩有兩種方式:

  • 使用原生 iOS UIAppearance protocol 以整體方式將所有可能的 UI 控制項樣式化。 這些設定可套用至許多 UI 控制項元素,但並非全部。

  • 在小工具類別上使用 SDK 方法,來設定 UIAppearance 通訊協定. 不支援的屬性。

一般而言,您的應用程式將使用 UIAppearance protocol 與 SDK 方法的組合。 下圖顯示哪些元素可以樣式化:

自動完成 UI 控制項色彩

下表列出所有 UI 元素,並指出每一個應如何樣式化(UIAppearance 通訊協定或 SDK 方法)。

UI 元素 方法 如何樣式化
導覽列著色(背景) UIAppearance 通訊協定 UINavigationBar Proxy 上呼叫 setBarTintColor
導覽列著色顏色(搜尋列文字色彩與取消按鈕) UIAppearance 通訊協定 UINavigationBar Proxy 上呼叫 setTintColor
搜尋列文字色彩 UIAppearance 通訊協定 searchBarTextAttributes 中設定 NSForegroundColorAttributeName
搜尋列著色顏色 不適用 搜尋列是半透明的,而且會顯示成有陰影的導覽列。
搜尋列預留位置文字色彩(預設搜尋文字) UIAppearance 通訊協定 placeholderAttributes 中設定 NSForegroundColorAttributeName
主要文字(也會套用至錯誤與訊息文字) SDK 方法 呼叫 primaryTextColor
主要文字醒目顯示 SDK 方法 呼叫 primaryTextHighlightColor
次要文字 SDK 方法 呼叫 secondaryTextColor
錯誤與訊息文字 SDK 方法 呼叫 primaryTextColor
表格儲存格背景 SDK 方法 呼叫 tableCellBackgroundColor
表格儲存格分隔符號色彩 SDK 方法 呼叫 tableCellSeparatorColor
"Try Again" 按鈕 SDK 方法 呼叫 tintColor
Activity 指示器(進度微調按鈕) UIAppearance 通訊協定 UIActivityIndicatorView Proxy 上呼叫 setColor
「Google 技術提供」標誌,悲傷雲影像 不適用 根據背景對比,自動選取白色或灰色版本。
在搜尋列文字欄位中的放大鏡與清除文字圖示 不適用 若要樣式化,請將預設影像取代為所需顏色的影像。

注意:這些屬性只會影響 UI 元素的色彩設定。 不支援變更 UI 元素大小,也不支援表格儲存格中使用的文字。

使用 UIAppearance 通訊協定

您可以使用 UIAppearance 通訊協定 來取得指定 UI 元素的外觀 Proxy,然後用它來設定 UI 元素的色彩。 當完成修改之後,指定 UI 元素的所有實例都會受影響。 例如,下列範例會將 UITextField 類別包含於 UISearchBar 中時的文字色彩全部變成綠色:

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

如需有關定義色彩值的詳細資訊,請參考 UIColor 類別參考

下列程式碼片段顯示用來將全螢幕自動完成 UI 控制項中所有項目樣式化所需的全部 Proxy 指令。 將此程式碼新增至 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;

Set UI 控制項樣式屬性

UI 控制項元素的子集具有不受 UIAppearance 通訊協定影響的屬性,因此必須直接設定。 下列程式碼範例顯示定義前景與背景色彩,並將那些色彩套用至名為 acController 的 UI 控制項實例。 將此程式碼新增至 ViewController.m 中的 onLaunchClicked 方法:

UIColor <em>darkGray = [UIColor darkGrayColor];
UIColor </em>lightGray = [UIColor lightGrayColor];</p>
<p>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;

注意:對於 GMSAutocompleteViewControllerGMSAutocompleteResultsViewController,您可以使用「介面建立器」來設定那些值。

以程式設計方式取得地點預測

您可以建立自訂搜尋 UI 做為自動完成小工具提供的替代 UI。 如果要這樣做,您的應用程式必須以程式設計方式取得地點預測。 透過下列方式之一,您的應用程式可以取得預測之地點名稱和/或地址的清單:

呼叫 GMSPlacesClient

如果要取得預測的地點名稱和/或地址的清單,請使用下列參數呼叫 GMSPlacesClient autocompleteQuery:bounds:filter:callback: 方法:

  • 包含使用者輸入之文字的 autocompleteQuery 字串。
  • GMSCoordinateBounds 物件,將結果偏移為由緯度與經度邊界所指定的特定地區。

  • 會將結果限制為特定類型地點的 GMSAutocompleteFilter。 如果要擷取所有類型,請提供零的值。 篩選器中支援下列地點類型:

    • kGMSPlacesAutocompleteTypeFilterNoFilter – 空白篩選器;會傳回所有結果。

    • kGMSPlacesAutocompleteTypeFilterGeocode – 只傳回地理編碼結果,而不傳回商家。 當指定的位置可能不明確時,可以使用此要求讓結果更加明確。

    • kGMSPlacesAutocompleteTypeFilterAddress – 只傳回具有精確地指的地理編碼結果。 當您知道使用者在尋找完整指定的地址時,便可以使用此要求。

    • kGMSPlacesAutocompleteTypeFilterEstablishment – 只傳回是商家的地點。

    • kGMSPlacesAutocompleteTypeFilterRegion – 只傳回符合下列其中一種類型的地點:

      • locality
      • sublocality
      • postal_code
      • country
      • administrative_area_level_1
      • administrative_area_level_2
    • kGMSPlacesAutocompleteTypeFilterCity – 只傳回符合 localityadministrative_area_level_3 的結果。

如需詳細資訊,請參閱地點類型

  • 用於處理所傳回預測的回呼方法。

下面的程式碼範例顯示對 autocompleteQuery:bounds:filter:callback: 的簡化呼叫。

Swift

func placeAutocomplete() {
  let filter = GMSAutocompleteFilter()
  filter.type = .establishment
  placesClient.autocompleteQuery("Sydney Oper", bounds: nil, filter: filter, callback: {(results, error) -> Void 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

- (void)placeAutocomplete {

GMSAutocompleteFilter *filter = [[GMSAutocompleteFilter alloc] init];
filter.type = kGMSPlacesAutocompleteTypeFilterEstablishment;

[_placesClient autocompleteQuery:@"Sydney Oper"
                          bounds:nil
                          filter:filter
                        callback:^(NSArray *results, NSError *error) {
                          if (error != nil) {
                            NSLog(@"Autocomplete error %@", [error localizedDescription]);
                            return;
                          }

                          for (GMSAutocompletePrediction* result in results) {
                            NSLog(@"Result '%@' with placeID %@", result.attributedFullText.string, result.placeID);
                          }
                        }];
}

API 會呼叫指定的回呼方法,傳入 GMSAutocompletePrediction 物件的陣列。

每個 GMSAutocompletePrediction 物件都包含下列資訊:

  • attributedFullText – 預測的全文(使用 NSAttributedString 的形式)。 例如,'Sydney Opera House, Sydney, New South Wales, Australia'。 每個符合使用者輸入的文字範圍都會有一個 kGMSAutocompleteMatchAttribute 屬性。 例如,您可以使用這個屬性,在使用者的查詢中醒目顯示相符的文字,如下所示。

  • placeID– 預測之地點的地點 ID。 地點 ID 是可唯一識別地點的文字型識別碼。 如需有關地點 ID 的詳細資訊,請參閱地點 ID 總覽

下列程式碼範例說明如何使用 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;
    

使用 Fetcher

如果您要從頭開始建置自己的自動完成控制項,可以使用 GMSAutocompleteFetcher,它會將 autocompleteQuery 方法包裝在 GMSPlacesClient 上。 Fetcher 會控制要求的速度,只傳回最近輸入之搜尋文字的結果。 它不提供 UI 元素。

如果要實作 GMSAutocompleteFetcher,請採取以下步驟:

  1. 實作 GMSAutocompleteFetcherDelegate 通訊協定。
  2. 建立 GMSAutocompleteFetcher 物件。
  3. 在 Fetcher 上呼叫 sourceTextHasChanged 做為使用者類型。
  4. 使用 didAutcompleteWithPredictionsdidFailAutocompleteWithError 通訊協定方法,來處理預測與錯誤。

下列程式碼範例示範使用 Fetcher 來取得使用者輸入,並在文字視圖中顯示符合的地點。 選取地點的功能已省略。 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)
    let bounds = GMSCoordinateBounds(coordinate: neBoundsCorner,
                                     coordinate: swBoundsCorner)

    // Set up the autocomplete filter.
    let filter = GMSAutocompleteFilter()
    filter.type = .establishment

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

    textField = UITextField(frame: CGRect(x: 5.0, y: 10.0,
                                          width: view.bounds.size.width - 5.0,
                                          height: 44.0))
    textField?.autoresizingMask = .flexibleWidth
    textField?.addTarget(self, action: #selector(textFieldDidChange(textField:)),
                         for: .editingChanged)

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

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

  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", prediction.attributedPrimaryText)
    }

    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);
  GMSCoordinateBounds *bounds = [[GMSCoordinateBounds alloc] initWithCoordinate:neBoundsCorner
                                                                     coordinate:swBoundsCorner];

  // Set up the autocomplete filter.
  GMSAutocompleteFilter *filter = [[GMSAutocompleteFilter alloc] init];
  filter.type = kGMSPlacesAutocompleteTypeFilterEstablishment;

  // Create the fetcher.
  _fetcher = [[GMSAutocompleteFetcher alloc] initWithBounds:bounds
                                                     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

設定自動完成的 GMSCoordinateBounds

您可以將 GMSCoordinateBounds 套用到自動完成,以提供的資訊引導完成。 例如,如果在您的檢視控制器中已經有 Google 地圖,您可以使用目前檢視點的邊界來調整自動完成的結果。

Swift

func placeAutocomplete() {
  let visibleRegion = mapView.projection.visibleRegion()
  let bounds = GMSCoordinateBounds(coordinate: visibleRegion.farLeft, coordinate: visibleRegion.nearRight)

  let filter = GMSAutocompleteFilter()
  filter.type = .establishment
  placesClient.autocompleteQuery("Sydney Oper", bounds: bounds, filter: filter, callback: {
    (results, error) -> Void in
    guard error == nil else {
      print("Autocomplete error \(error)")
      return
    }
    if let results = results {
      for result in results {
        print("Result \(result.attributedFullText) with placeID \(result.placeID)")
      }
    }
  })
}

Objective-C

- (void)placeAutocomplete {

GMSVisibleRegion visibleRegion = self.mapView.projection.visibleRegion;
GMSCoordinateBounds *bounds = [[GMSCoordinateBounds alloc] initWithCoordinate:visibleRegion.farLeft
                                                                   coordinate:visibleRegion.nearRight];
GMSAutocompleteFilter *filter = [[GMSAutocompleteFilter alloc] init];
filter.type = kGMSPlacesAutocompleteTypeFilterEstablishment;

[_placesClient autocompleteQuery:@"Sydney Oper"
                          bounds:bounds
                          filter:filter
                        callback:^(NSArray *results, NSError *error) {
                          if (error != nil) {
                            NSLog(@"Autocomplete error %@", [error localizedDescription]);
                            return;
                          }

                          for (GMSAutocompletePrediction* result in results) {
                            NSLog(@"Result '%@' with placeID %@", result.attributedFullText.string, result.placeID);
                          }
                        }];
}

使用限制

在應用程式中顯示資料引用標示

  • 如果您的應用程式以程式設計方式使用自動完成服務,那麼您的 UI 就必須顯示「Google 技術提供」資料引用標示,或是出現在 Google 品牌地圖中。
  • 如果您的應用程式使用自動完成 UI 控制項,則不需要額外動作(預設會顯示必要的資料引用標示)。

  • 如果您在依 ID 取得地點 之後擷取並顯示額外的地點資訊,您也必須顯示第三方資料引用標示。

如需詳細資料,請參閱有關資料引用標示 的文件。

控制網路 Activity 指示器

如果要控制應用程式狀態列中的網路 Activity 指示器,您必須針對要使用的自動完成類別,實作適當的選擇性委派方法,並自行開啟及關閉網路指示器。

  • 對於 GMSAutocompleteViewController,您必須實作委派方法 didRequestAutocompletePredictions:didUpdateAutocompletePredictions:
  • 對於 GMSAutocompleteResultsViewController,您必須實作委派方法 didRequestAutocompletePredictionsForResultsController:didUpdateAutocompletePredictionsForResultsController:
  • 對於 GMSAutocompleteTableDataSource,您必須實作委派方法 didRequestAutocompletePredictionsForTableDataSource:didUpdateAutocompletePredictionsForTableDataSource:

透過實作這些方法,以及將 [UIApplication sharedApplication].networkActivityIndicatorVisible 分別設定為 YESNO,狀態列將會正確符合自動完成 UI。

疑難排解

雖然有可能發生各類錯誤,不過您的應用程式可能遇到的大多數錯誤通常是設定錯誤所造成的(例如,使用錯誤的 API 金鑰,或是 API 金鑰設定錯誤),或是配額錯誤(您的應用程式已超過其配額)。 如需有關配額的詳細資訊,請參閱使用限制

使用自動完成控制項時發生的錯誤,會在各種委派通訊協定的 didFailAutocompleteWithError() 方法中傳回。 所提供的 NSError 物件的 code 屬性是設定為 GMSPlacesErrorCode 列舉的其中一個值。

傳送您對下列選項的寶貴意見...

這個網頁
location_on
Google Places API for iOS