以上で完了です。

開発を始めるには、デベロッパー ドキュメント をご覧下さい。

Google Places API for iOS をアクティベートする

まず初めに Google Developers Console で次の作業を行います。

  1. プロジェクトを作成または選択する
  2. Google Places API for iOS をアクティベートする
  3. 適切なキーを作成する
続ける

プレイス オートコンプリート

Google Places API for iOS のオートコンプリート サービスでは、ユーザーの検索クエリに対して、プレイスの予測結果を返します。 オートコンプリート サービスは、ユーザーが入力している最中に、お店やサービス、住所、有名なスポットなど、プレイスの候補を返します。

次の方法でアプリにオートコンプリート機能を追加することができます。

オートコンプリート UI コントロールを追加する

オートコンプリート UI コントロールは、組み込みのオートコンプリート機能が含まれた検索ダイアログです。 ユーザーが検索キーワードを入力すると、予測されるプレイスのリストが表示され、そこからプレイスを選択できます。 ユーザーがプレイスを選択すると、GMSPlace インスタンスが返されます。その後、アプリはこのインスタンスを使用して、選択されたプレイスの詳細を取得できます。

次の方法でアプリにオートコンプリート UI コントロールを追加することができます。

フルスクリーン コントロールを追加する

モーダル コンテキストが必要な場合は、フルスクリーン コントロールを使用します。この機能を使用すると、ユーザーが選択を完了するまで、アプリの UI がオートコンプリート UI に一時的に置き替えられます。 この機能は GMSAutocompleteViewController クラスによって提供されます。 ユーザーがプレイスを選択すると、アプリはコールバックを受け取ります。

フルスクリーン コントロールをアプリに追加するには:

  1. メインのアプリで UI 要素(UIButton のタッチ ハンドラなど)を作成して、オートコンプリート UI コントロールを起動します。

  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. GMSAutocompleteResultsViewControllerUISearchControllersearchResultsUpdater プロパティとして設定します。

  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. 親ビュー コントローラに GMSAutocompleteTableDataSourceDelegate および UISearchDisplayDelegate プロトコルを実装します。

  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 プロトコルの didUpdateAutocompletePredictions および didRequestAutocompletePredictions メソッドでテーブルデータを再読み込みして、強制的にテーブルをアップデートする必要があります。

テキストと背景の色をカスタマイズする

オートコンプリート UI コントロールのすべてのテキストと背景の色を設定して、できるだけウィジェットがアプリの外観になじむようにします。 UI コントロールの色を設定するには、次の 2 つの方法があります。

  • ネイティブ iOS UIAppearance プロトコルを使用して、できるだけ広い範囲で UI コントロールのスタイルを設定します。 これらの設定は、UI コントロールの多くの要素に適用されますが、すべての要素には適用されません。

  • ウィジェット クラスで SDK メソッドを使用して、UIAppearance プロトコルの対象外とするプロパティを設定します。

通常、アプリでは、UIAppearance プロトコルと SDK メソッドを組み合わせて使用します。 次の図は、スタイル設定が可能な要素を示しています。

オートコンプリート UI コントロールの色

次の表には、すべての UI 要素のリストと、UIAppearance プロトコルまたは SDK メソッドで各要素をスタイル設定する方法が示されています。

UI 要素 メソッド スタイル設定する方法
ナビゲーション バーの濃淡(背景) UIAppearance プロトコル UINavigationBar プロキシで setBarTintColor を呼び出します。
ナビゲーション バーの濃淡色(検索バーのテキスト キャレットと [Cancel] ボタン) UIAppearance プロトコル UINavigationBar プロキシで setTintColor を呼び出します。
検索バーのテキストの色 UIAppearance プロトコル searchBarTextAttributesNSForegroundColorAttributeName を設定します。
検索バーの濃淡色 該当せず 検索バーは半透明であり、ナビゲーション バーの影付きバージョンとして表示されます。
検索バーのプレースホルダ テキストの色(デフォルトの検索テキスト) UIAppearance プロトコル placeholderAttributesNSForegroundColorAttributeName を設定します。
プライマリ テキスト(エラーとメッセージのテキストにも適用される) SDK メソッド primaryTextColor を呼び出します。
プライマリ テキストのハイライト表示 SDK メソッド primaryTextHighlightColor を呼び出します。
セカンダリ テキスト SDK メソッド secondaryTextColor を呼び出します。
エラーとメッセージのテキスト SDK メソッド primaryTextColor を呼び出します。
テーブルセルの背景 SDK メソッド tableCellBackgroundColor を呼び出します。
テーブルセルのセパレータの色 SDK メソッド tableCellSeparatorColor を呼び出します。
[Try Again] ボタン SDK メソッド tintColor を呼び出します。
アクティビティのインジケーター(進捗インジケーター) UIAppearance プロトコル UIActivityIndicatorView プロキシで setColor を呼び出します。
「Powered by Google」ロゴ、Sad cloud 画像 該当せず 背景とのコントラストを基準に、白または灰色のバージョンが自動的に選択されます。
検索バーのテキスト フィールドの虫メガネとテキスト削除のアイコン 該当せず スタイル設定するには、デフォルトの画像を目的の色の画像に置き替えます。

注: これらのプロパティは、UI 要素の色設定のみに効果があります。 UI 要素のサイズ変更やテーブルセルで使用されるフォントの変更はサポートされていません。

UIAppearance プロトコルを使用する

UIAppearance プロトコルを使用して、任意の UI 要素のアピアランス プロキシを取得できます。このプロキシを使用して、UI 要素の色を設定します。 変更が完了すると、任意の UI 要素のすべてのインスタンスが影響を受けます。 たとえば、次の例は、UITextField クラスが UISearchBar に含まれている場合、これらのクラスのテキスト色を全体的に緑に変更します。

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

色の値の定義に関する詳細については、UIColor クラス リファレンスをご覧ください。

次のコード スニペットは、フルスクリーンのオートコンプリート UI コントロールの全要素をスタイル設定するために必要なすべてのプロキシ コマンドを示しています。 このコードを 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;

UI コントロールのスタイル プロパティを設定する

UI コントロール要素のサブセットには、UIAppearance プロトコルの影響を受けないプロパティがあります。そのため、これらのプロパティは直接設定する必要があります。 次のコードサンプルは、前景色と背景色を定義し、これらの色を acController という名前の UI コントロール インスタンスに適用する方法を示しています。 このコードを 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;

注: GMSAutocompleteViewControllerGMSAutocompleteResultsViewController の場合は、Interface Builder を使用して、これらの値を設定することができます。

プログラムでプレイスの予測結果を取得する

オートコンプリート ウィジェットで提供される UI の代わりに、カスタムの検索 UI を作成できます。 この UI を作成するには、アプリのプログラムでプレイスの予測結果を取得する必要があります。 次のいずれかの方法を使って、予測されるプレイスの名前や住所のリストをアプリで取得することができます。

GMSPlacesClient を呼び出す

予測されるプレイスの名前や住所のリストを取得するには、GMSPlacesClient autocompleteQuery:bounds:filter:callback: メソッドを呼び出して、次のパラメータを渡します。

  • ユーザーが入力したテキストを含む autocompleteQuery 文字列。
  • 緯度と経度の範囲で指定した特定のエリアの結果を優先させる GMSCoordinateBounds オブジェクト。

  • 特定のプレイスタイプに結果を制限する GMSAutocompleteFilter。 すべてのタイプを取得するには、nil 値を渡します。 次のプレイスタイプがフィルタでサポートされています。

    • kGMSPlacesAutocompleteTypeFilterNoFilter – 空のフィルタ。すべての結果が返されます。

    • kGMSPlacesAutocompleteTypeFilterGeocode – お店やサービスの情報は返されず、ジオコーディングの結果のみが返されます。 このリクエストは、はっきり特定できない場所を明確にするために使用します。

    • kGMSPlacesAutocompleteTypeFilterAddress – 正確な住所が示されたオートコンプリートの結果のみを返します。 このタイプのリクエストは、ユーザーが完全な住所を指定して検索することがわかっている場合に使用します。

    • kGMSPlacesAutocompleteTypeFilterEstablishment – お店やサービスのプレイスのみを返します。

    • kGMSPlacesAutocompleteTypeFilterRegion – 次のいずれかのタイプに一致するプレイスのみを返します。

      • locality
      • sublocality
      • postal_code
      • country
      • administrative_area_level_1
      • administrative_area_level_2
    • kGMSPlacesAutocompleteTypeFilterCitylocality または administrative_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 オブジェクトには、次の情報が含まれます。

  • attributedFullTextNSAttributedString 形式の予測結果のフルテキストです。 たとえば、「Sydney Opera House, Sydney, New South Wales, Australia」などです。 ユーザーが入力した値と一致するテキスト範囲にはすべて kGMSAutocompleteMatchAttribute 属性があります。 この属性を使用して、以下のようにユーザーのクエリで一致するテキストをハイライト表示することもできます。

  • placeID – 予測されるプレイスのプレイス ID。 プレイス 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;
    

フェッチャーを使用する

独自のオートコンプリート コントロールを一からビルドする場合は、GMSPlacesClientautocompleteQuery メソッドをラップする GMSAutocompleteFetcher を使用できます。

フェッチャーはリクエストを調整して、直近に入力された検索テキストに対する結果のみを返します。 UI 要素は提供されません。

GMSAutocompleteFetcher を実装するには、次の手順を実行します。

  1. GMSAutocompleteFetcherDelegate プロトコルを実装します。

  2. GMSAutocompleteFetcher オブジェクトを作成します。

  3. ユーザーの入力時にフェッチャーで sourceTextHasChanged を呼び出します。
  4. didAutcompleteWithPredictions および didFailAutocompleteWithError プロトコルのメソッドを使用して、予測結果とエラーを処理します。

次のコードサンプルは、フェッチャーを使用して、ユーザー入力を取得し、一致したプレイスをテキストビューで表示する方法を示しています。 プレイスを選択する機能は省略されています。 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 に "Powered by Google" の帰属情報を表示するか、UI を Google ブランドマップ内に表示する必要があります。

  • アプリでオートコンプリート UI コントロールを使用する場合は、追加の対応は必要ありません(必要な帰属情報がデフォルトで表示されます)。

  • ID でプレイスを取得した後、追加のプレイス情報を取得して表示する場合は、サードパーティの帰属表示も必要です。

詳細については、属性をご覧ください。

ネットワーク アクティビティ インジケーターを制御する

アプリのステータスバーにあるネットワーク アクティビティ インジケーターを制御するには、使用しているオートコンプリート クラス用に適切なオプションのデリゲート メソッドを実装して、ネットワーク インジケーターをオンまたはオフにする必要があります。

  • GMSAutocompleteViewController の場合は、didRequestAutocompletePredictions: および didUpdateAutocompletePredictions: デリゲート メソッドを実装する必要があります。
  • GMSAutocompleteResultsViewController の場合は、didRequestAutocompletePredictionsForResultsController: および didUpdateAutocompletePredictionsForResultsController: デリゲート メソッドを実装する必要があります。
  • GMSAutocompleteTableDataSource の場合は、didRequestAutocompletePredictionsForTableDataSource: および didUpdateAutocompletePredictionsForTableDataSource: デリゲート メソッドを実装する必要があります。

これらのメソッドを実装して、[UIApplication sharedApplication].networkActivityIndicatorVisibleYESNO にそれぞれ設定すると、ステータスバーの表示がオートコンプリート UI に正しく適合するようになります。

トラブルシューティング

さまざまなエラーが発生する可能性がありますが、一般的にアプリでよく発生するエラーの主な原因は、設定エラー(誤った API キーが使用された、API キーが正しく設定されていないなど)または割り当てエラー(アプリで割り当てを超過した)です。

割り当ての詳細については、使用制限をご覧ください。

オートコンプリート コントロールの使用時に発生するエラーは、さまざまなデリゲート プロトコルの didFailAutocompleteWithError() メソッドで返されます。 指定された NSError オブジェクトの code プロパティは、GMSPlacesErrorCode 列挙型のいずれかの値に設定されます。

フィードバックを送信...