You're all set!

To start developing, please head over to our developer documentation.

Activate the Google Places API for iOS

To get you started we'll guide you through the Google Developers Console to do a few things first:

  1. Create or choose a project
  2. Activate the Google Places API for iOS
  3. Create appropriate keys
Continue

Place Autocomplete

The autocomplete service in the Google Places API for iOS returns place predictions in response to user search queries. As the user types, the autocomplete service returns suggestions for places such as businesses, addresses and points of interest.

You can add autocomplete to your app in the following ways:

Add an autocomplete UI control

The autocomplete UI control is a search dialog with built-in autocomplete functionality. As a user enters search terms, the control presents a list of predicted places to choose from. When the user makes a selection, a GMSPlace instance is returned, which your app can then use to get details about the selected place.

You can add the autocomplete UI control to your app in the following ways:

Add a full-screen control

Use the full-screen control when you want a modal context, where the autocomplete UI temporarily replaces the UI of your app until the user has made their selection. This functionality is provided by the GMSAutocompleteViewController class. When the user selects a place, your app receives a callback.

To add a full-screen control to your app:

  1. Create a UI element in your main app to launch the autocomplete UI control, for example a touch handler on a UIButton.
  2. Implement the GMSAutocompleteViewControllerDelegate protocol in the parent view controller.
  3. Create an instance of GMSAutocompleteViewController and assign the parent view controller as the delegate property.
  4. Present the GMSAutocompleteViewController using [self presentViewController...].
  5. Handle the user's selection in the didAutocompleteWithPlace delegate method.
  6. Dismiss the controller in the didAutocompleteWithPlace, didFailAutocompleteWithError, and wasCancelled delegate methods.

The following example demonstrates one possible way to launch GMSAutocompleteViewController in response to the user tapping on a button.

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

Add a results controller

Use a results controller when you want more control over the text input UI. The results controller dynamically toggles the visibility of the results list based on input UI focus.

To add a results controller to your app:

  1. Create a GMSAutocompleteResultsViewController.
  2. Implement the GMSAutocompleteResultsViewControllerDelegate protocol in the parent view controller and assign the parent view controller as the delegate property.
  3. Create a UISearchController object, passing in the GMSAutocompleteResultsViewController as the results controller argument.
  4. Set the GMSAutocompleteResultsViewController as the searchResultsUpdater property of the UISearchController.
  5. Add the searchBar for the UISearchController to your app's UI.
  6. Handle the user's selection in the didAutocompleteWithPlace delegate method.

There are several ways to place the search bar of a UISearchController into your app's UI:

Add a search bar to the navigation bar

The following code example demonstrates adding a results controller, adding the searchBar to the navigation bar, and handling the user's selection:

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;
}

Add a search bar to the top of a view

The following code example shows adding the searchBar to the top of a view.

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;
}

By default, UISearchController hides the navigation bar when presenting (this can be disabled). In cases where the navigation bar is visible and opaque, UISearchController does not set the placement correctly. Use the following code as a workaround:

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;

Add a search bar using popover results

The following code example shows placing a search bar on the right side of the navigation bar, and displaying results in a popover.

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;
}

Use a table data source

If your app must support iOS 7, you can use the GMSAutocompleteTableDataSource class to drive the table view of a UISearchDisplayController.

To use GMSAutocompleteTableDataSource to display a search controller:

  1. Implement the GMSAutocompleteTableDataSourceDelegate and UISearchDisplayDelegate protocols in the parent view controller.
  2. Create a GMSAutocompleteTableDataSource instance and assign the parent view controller as the delegate property.
  3. Create an instance of UISearchDisplayController.
  4. Add the searchBar for the UISearchController to your app's UI.
  5. Handle the user's selection in the didAutocompleteWithPlace delegate method.
  6. Dismiss the controller in the didAutocompleteWithPlace, didFailAutocompleteWithError, and wasCancelled delegate methods.

The following code example demonstrates using the GMSAutocompleteTableDataSource class to drive the table view of a 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];
}

Customize text and background colors

You can set the colors of all text and backgrounds in the autocomplete UI control, to make the widget match the visual appearance of your app more closely. There are two ways to set the UI control colors:

  • By using the native iOS UIAppearance protocol to globally style UI controls where possible. These settings apply to many, but not all, of the UI control elements.
  • By using the SDK methods on the widget classes to set properties which are not supported by the UIAppearance protocol.

Typically, your app will use some combination of the UIAppearance protocol and the SDK methods. The following diagram shows which elements can be styled:

Autocomplete UI control colors

The following table lists all of the UI elements, and indicates how each one should be styled (UIAppearance protocol or SDK method).

UI Element Method How to style
Navigation Bar tint (background) UIAppearance protocol Call setBarTintColor on UINavigationBar proxy.
Navigation Bar tint color (search bar text caret and Cancel button) UIAppearance protocol Call setTintColor on UINavigationBar proxy.
Search Bar text color UIAppearance protocol Set NSForegroundColorAttributeName in searchBarTextAttributes.
Search bar tint color N/A The search bar is translucent, and will display as a shaded version of the Navigation Bar.
Search bar placeholder text color (default search text) UIAppearance protocol Set NSForegroundColorAttributeName in placeholderAttributes.
Primary text (also applied to error and message text) SDK method Call primaryTextColor.
Primary text highlight SDK method Call primaryTextHighlightColor.
Secondary text SDK method Call secondaryTextColor.
Error and message text SDK method Call primaryTextColor.
Table cell background SDK method Call tableCellBackgroundColor.
Table cell separator color SDK method Call tableCellSeparatorColor.
"Try Again" button SDK method Call tintColor.
Activity indicator (progress spinner) UIAppearance protocol Call setColor on UIActivityIndicatorView proxy.
"Powered by Google" logo, Sad cloud image N/A White or gray version is automatically selected based on background contrast.
Magnifying glass and clear text icons in Search Bar text field N/A To style, replace the default images with images of the desired color.

Use the UIAppearance protocol

You can use the UIAppearance protocol to get the appearance proxy for a given UI element, which you can then use to set the color for the UI element. When a modification is made, all instances of a given UI element are affected. For example, the following example globally changes the text color of UITextField classes to green when they are contained in a UISearchBar:

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

For more information about defining color values, consult the UIColor Class Reference.

The following code snippets show all of the proxy commands you need to use to style everything in the full-screen autocomplete UI control. Add this code to the didFinishLaunchingWithOptions method in Appdelegate.m:

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

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

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

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

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

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

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

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

Set UI control style properties

A subset of UI control elements have properties that are not affected by the UIAppearance protocol, and so must be set directly. The following code example shows defining foreground and background colors, and applying them to a UI control instance named acController. Add this code to the onLaunchClicked method in ViewController.m:

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;

Get place predictions programmatically

You can create a custom search UI as an alternative to the UI provided by the autocomplete widget. To do this, your app must get place predictions programmatically. Your app can get a list of predicted place names and/or addresses in one of the following ways:

Call GMSPlacesClient

To get a list of predicted place names and/or addresses, call the GMSPlacesClient autocompleteQuery:bounds:filter:callback: method with the following parameters:

  • An autocompleteQuery string containing the text typed by the user.
  • A GMSCoordinateBounds object biasing the results to a specific area specified by latitude and longitude bounds.
  • A GMSAutocompleteFilter restricting the results to a specific type of place. To retrieve all types, supply a value of nil. The following place types are supported in the filter:

    • kGMSPlacesAutocompleteTypeFilterNoFilter – An empty filter; all results are returned.
    • kGMSPlacesAutocompleteTypeFilterGeocode – Returns only geocoding results, rather than businesses. Use this request to disambiguate results where the specified location may be indeterminate.
    • kGMSPlacesAutocompleteTypeFilterAddress – Returns only autocomplete results with a precise address. Use this type when you know the user is looking for a fully specified address.
    • kGMSPlacesAutocompleteTypeFilterEstablishment – Returns only places that are businesses.
    • kGMSPlacesAutocompleteTypeFilterRegion – Returns only places that match one of the following types:

      • locality
      • sublocality
      • postal_code
      • country
      • administrative_area_level_1
      • administrative_area_level_2
    • kGMSPlacesAutocompleteTypeFilterCity – Returns only results matching locality or administrative_area_level_3.

For more information, see place types.

  • A callback method to handle the returned predictions.

The code examples below show a simplified call to 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);
                          }
                        }];
}

The API invokes the specified callback method, passing in an array of GMSAutocompletePrediction objects.

Each GMSAutocompletePrediction object contains the following information:

  • attributedFullText – The full text of the prediction, in the form of an NSAttributedString. For example, 'Sydney Opera House, Sydney, New South Wales, Australia'. Every text range that matches the user input has an attribute, kGMSAutocompleteMatchAttribute. You can use this attribute to highlight the matching text in the user's query, for example, as shown below.
  • placeID – The place ID of the predicted place. A place ID is a textual identifier that uniquely identifies a place. For more information about place IDs, see the Place ID overview.

The following code example illustrates how to highlight in bold text the parts of the result that match text in the user's query, using 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;
    

Use the fetcher

If you want to build your own autocomplete control from scratch, you can use GMSAutocompleteFetcher, which wraps the autocompleteQuery method on GMSPlacesClient. The fetcher throttles requests, returning only results for the most recently entered search text. It provides no UI elements.

To implement GMSAutocompleteFetcher, take the following steps:

  1. Implement the GMSAutocompleteFetcherDelegate protocol.
  2. Create a GMSAutocompleteFetcher object.
  3. Call sourceTextHasChanged on the fetcher as the user types.
  4. Handle predictions and errors using the didAutcompleteWithPredictions and didFailAutocompleteWithError protocol methods.

The following code example demonstrates using the fetcher to take user input and display place matches in a text view. Functionality for selecting a place has been omitted. FetcherSampleViewController derives from UIViewController in FetcherSampleViewController.h.

Swift

import UIKit
import GooglePlaces

class ViewController: UIViewController {

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

  override func viewDidLoad() {
    super.viewDidLoad()

    view.backgroundColor = .white
    edgesForExtendedLayout = []

    // Set bounds to inner-west Sydney Australia.
    let neBoundsCorner = CLLocationCoordinate2D(latitude: -33.843366,
                                                longitude: 151.134002)
    let swBoundsCorner = CLLocationCoordinate2D(latitude: -33.875725,
                                                longitude: 151.200349)
    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

Set the GMSCoordinateBounds of autocomplete

You can supply a GMSCoordinateBounds to autocomplete to guide the supplied completions. For example, if you already have a Google Map in your view controller, you can use the bounds of the current viewport to bias autocomplete results.

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);
                          }
                        }];
}

Usage limits

Display attributions in your app

  • If your app uses the autocomplete service programmatically, your UI must either display a 'Powered by Google' attribution, or appear within a Google-branded map.
  • If your app uses the autocomplete UI control no additional action is required (the required attribution is displayed by default).
  • If you retrieve and display additional place information after getting a place by ID, you must display third-party attributions too.

For more details, see the documentation on attributions.

Controlling the network activity indicator

To control the network activity indicator in the applications status bar you must implement the appropriate optional delegate methods for the autocomplete class you are using and turn the network indicator on and off yourself.

  • For GMSAutocompleteViewController you must implement the delegate methods didRequestAutocompletePredictions: and didUpdateAutocompletePredictions:.
  • For GMSAutocompleteResultsViewController you must implement the delegate methods didRequestAutocompletePredictionsForResultsController: and didUpdateAutocompletePredictionsForResultsController:.
  • For GMSAutocompleteTableDataSource you must implement the delegate methods didRequestAutocompletePredictionsForTableDataSource: and didUpdateAutocompletePredictionsForTableDataSource:.

By implementing these methods and setting [UIApplication sharedApplication].networkActivityIndicatorVisible to YES and NO respectively the status bar will correctly match the autocomplete UI.

Troubleshooting

Although a wide variety of errors can occur, the majority of the errors your app is likely to experience are usually caused by configuration errors (for example, the wrong API key was used, or the API key was configured incorrectly), or quota errors (your app has exceeded its quota). See Usage Limits for more information about quotas.

Errors that occur in the use of the autocomplete controls are returned in the didFailAutocompleteWithError() method of the various delegate protocols. The code property of the supplied NSError object is set to one of the values of the GMSPlacesErrorCode enumeration.

Send feedback about...

location_on
Google Places API for iOS