Pronto!

Para começar a desenvolver, acesse nossa documentação do desenvolvedor.

Ativar a API do Google Places para iOS

Para começar, orientaremos você pelo Console de Desenvolvedores do Google para realizar algumas atividades:

  1. Criar ou selecionar um projeto
  2. Ativar a API do Google Places para iOS
  3. Criar chaves apropriadas
Continuar

Place Autocomplete

O serviço de preenchimento automático na Google Places API for iOS retorna sugestões de local em resposta a consultas de pesquisa do usuário. Enquanto o usuário digita, o serviço de preenchimento automático retorna sugestões de locais, como estabelecimentos, endereços e pontos de interesse.

É possível adicionar o preenchimento automático no aplicativo das seguintes formas:

Adicionar um widget de preenchimento automático

O widget de preenchimento automático é uma caixa de diálogo de pesquisa com o recurso do preenchimento automático integrado. Conforme o usuário digita termos de pesquisa, o widget apresenta uma lista de locais sugeridos para escolher. Quando o usuário seleciona um deles, uma instância de GMSPlace é retornada, que, em seguida, o aplicativo pode usar para obter detalhes sobre o local selecionado.

É possível adicionar o widget de preenchimento automático do seu aplicativo das seguintes formas:

Adicionar um widget de tela cheia

Use o widget de tela cheia quando quiser oferecer contexto modal, em que a IU de preenchimento automático substitui temporariamente a IU do aplicativo até o usuário fazer a seleção. Essa funcionalidade é providenciada pela classe GMSAutocompleteViewController. Quando o usuário seleciona um local, o aplicativo recebe um retorno de chamada.

Para adicionar um widget de tela cheia ao aplicativo:

  1. Crie um elemento de IU no aplicativo principal para inicializar o widget de preenchimento automático, por exemplo, um manipulador de toque em um UIButton.
  2. Implemente o protocolo GMSAutocompleteViewControllerDelegate no controlador de visualizações primário.
  3. Crie uma instância de GMSAutocompleteViewController e defina o controlador de visualizações primário como a propriedade “delegate”.
  4. Apresente o GMSAutocompleteViewController usando [self presentViewController...].
  5. Manipule a seleção do usuário no método delegado didAutocompleteWithPlace.
  6. Descarte o controlador nos métodos delegados didAutocompleteWithPlace, didFailAutocompleteWithError e wasCancelled.

O exemplo a seguir demonstra uma forma possível de inicializar GMSAutocompleteViewController em resposta ao toque do usuário em um botão.

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

Adicionar um controlador de resultados

Use um controlador de resultados quando quiser ter mais controle sobre a IU de inserção de texto. O controlador de resultados altera a exibição da lista de resultados com base no foco da IU de interação do usuário.

Para adicionar um controlador de resultados ao aplicativo:

  1. Crie um GMSAutocompleteResultsViewController.
  2. Implemente o protocolo GMSAutocompleteResultsViewControllerDelegate no controlador de visualizações primário e defina-o como a propriedade “delegate”.
  3. Crie um objeto UISearchController, passando-o no GMSAutocompleteResultsViewController como o argumento do controlador de resultados.
  4. Defina GMSAutocompleteResultsViewController como a propriedade searchResultsUpdater do UISearchController.
  5. Adicione a searchBar do UISearchController à IU do aplicativo.
  6. Manipule a seleção do usuário no método delegado didAutocompleteWithPlace.

Há diversas maneiras de colocar a barra de pesquisa de um UISearchController na IU do aplicativo:

Adicionar uma barra de pesquisa à barra de navegação

O exemplo de código a seguir demonstra como adicionar um controlador de resultados, adicionando a searchBar à barra de navegação e tratando da seleção do usuário:

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

Observação: Para que a barra de pesquisa seja exibida corretamente, o controlador de visualizações do seu aplicativo deve ser estar contido em um UINavigationController.

Adicionar uma barra de pesquisa no topo de uma tela

O exemplo de código a seguir mostra como adicionar a searchBar ao topo de uma tela.

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

Por padrão, UISearchController esconde a barra de navegação quando se apresenta (esse comportamento pode ser desativado). Em casos em que a barra de navegação está visível e opaca, UISearchController não configura a colocação corretamente. Use o código a seguir como solução alternativa:

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;

Adicionar uma barra de pesquisa usando resultados popover

O exemplo de código a seguir mostra como colocar uma barra de pesquisa no lado direito da barra de navegação e exibir os resultados em uma 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;
}

Observação: Para que a barra de pesquisa seja exibida corretamente, o controlador de visualizações do seu aplicativo deve ser estar contido em um UINavigationController.

Usar uma fonte de dados de tabela

Se o seu aplicativo precisa oferecer suporte a iOS 7, use a classe GMSAutocompleteTableDataSource para gerar a visualização de tabela de um UISearchDisplayController.

Para usar GMSAutocompleteTableDataSource para exibir um controlador de pesquisa:

  1. Implemente os protocolos GMSAutocompleteTableDataSourceDelegate e UISearchDisplayDelegate no controlador de visualizações primário.
  2. Crie uma instância de GMSAutocompleteTableDataSource e defina o controlador de visualizações primário como a propriedade “delegate”.
  3. Crie uma instância de UISearchDisplayController.
  4. Adicione a searchBar do UISearchController à IU do aplicativo.
  5. Manipule a seleção do usuário no método delegado didAutocompleteWithPlace.
  6. Descarte o controlador nos métodos delegados didAutocompleteWithPlace, didFailAutocompleteWithError e wasCancelled.

O exemplo de código a seguir demonstra como usar a classe GMSAutocompleteTableDataSource para gerar a visualização de tabela de um 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];
}

Observação: A API UISearchDisplayController não é compatível com o conceito de atualizações de dados assíncronas, por isso é necessário forçar atualizações da tabela recarregando os dados dela nos métodos didUpdateAutocompletePredictions e didRequestAutocompletePredictions do protocolo GMSAutoCompleteResultsDelegate.

Personalizar cores de texto e de fundo

Você pode definir cor para todos os textos e planos de fundo no widget de preenchimento automático para fazê-lo combinar com o visual geral do aplicativo. Há duas formas de definir as cores do widget:

  • Usando o protocolo UIAppearance nativo do iOS para aplicar estilo padrão nos widgets em todos os casos possíveis. Essas configurações se aplicam a muitos, mas não a todos os elementos do widget.
  • Usando os métodos do SDK nas classes do widget para definir propriedades não compatíveis com o protocolo UIAppearance.

Normalmente, o aplicativo usa uma combinação do protocolo UIAppearance e os métodos do SDK. O diagrama a seguir mostra que elementos podem ser estilizados:

Cores do widget de preenchimento automático

A tabela a seguir lista todos os elementos da IU e indica como cada um deve ser estilizado (protocolo UIAppearance ou método SDK).

Elemento da IU Método Como aplicar estilo
Cor da barra de navegação (fundo) Protocolo UIAppearance Chame setBarTintColor no proxy de UINavigationBar.
Cor da barra de navegação (circunflexo no texto da barra de pesquisa e botão de cancelar) Protocolo UIAppearance Chame setTintColor no proxy de UINavigationBar.
Cor do texto da barra de pesquisa Protocolo UIAppearance Defina NSForegroundColorAttributeName em searchBarTextAttributes.
Tom da cor da barra de pesquisa N/A A barra de pesquisa é translúcida e será exibida como uma versão escurecida da barra de navegação.
Cor do texto do marcador da barra de pesquisa (texto de pesquisa padrão) Protocolo UIAppearance Defina NSForegroundColorAttributeName em placeholderAttributes.
Texto principal (também aplicado a texto de erros e mensagens) Método do SDK Chame primaryTextColor.
Realce do texto principal Método do SDK Chame primaryTextHighlightColor.
Texto secundário Método do SDK Chame secondaryTextColor.
Texto de erros e mensagens Método do SDK Chame primaryTextColor.
Fundo das células da tabela Método do SDK Chame tableCellBackgroundColor.
Cor da borda das células da tabela Método do SDK Chame tableCellSeparatorColor.
Botão “Try Again” Método do SDK Chame tintColor.
Indicador de atividade (ícone de status de carregamento) Protocolo UIAppearance Chame setColor no proxy de UIActivityIndicatorView.
Logotipo “Tecnologia do Google”, imagem de nuvem triste N/A Versão branca ou cinza automaticamente selecionada de acordo com o contraste com o plano de fundo.
Ícones de lupa e apagar texto no campo de texto da barra de pesquisa N/A Para aplicar estilo, substitua as imagens padrão por imagens da cor desejada.

Observação: Essas propriedades só afetam as configurações de cor dos elementos da IU. Não é possível alterar o tamanho dos elementos da IU nem a fonte usada nas células da tabela.

Usar o protocolo UIAppearance

Você pode usar o protocolo UIAppearance para obter o proxy de aparência de determinado elemento da IU, que pode ser usado para definir a cor deste elemento. Ao promover uma modificação, todas as instâncias de um dado elemento de IU são afetadas. Por exemplo, o exemplo a seguir altera, em todos os casos, a cor do texto das classes UITextField para verde quando elas estão contidas em uma UISearchBar:

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

Para saber mais sobre como definir valores de cor, consulte o Guia da classe UIColor.

Os snippets de código a seguir mostram todos os comandos de proxy necessários para aplicar estilo a todos os componentes do widget de preenchimento automático em tela cheia. Adicione este código ao método didFinishLaunchingWithOptions em 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;

Configurar propriedades de estilo do widget

Um subconjunto de elementos do widget têm propriedades que não são afetadas pelo protocolo UIAppearance, portanto deve ser definido diretamente. O exemplo de código a seguir mostra como definir cores para o plano principal e o plano de fundo e aplicá-las a uma instância do widget chamada acController. Adicione este código ao método onLaunchClicked em 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;

Observação: Para GMSAutocompleteViewController e GMSAutocompleteResultsViewController, você pode usar o Interface Builder para definir esses valores.

Obter sugestões de local programaticamente

É possível criar uma IU de pesquisa personalizada como alternativa à IU fornecida pelo widget de preenchimento automático. Para tanto, o aplicativo precisa receber sugestões de local programaticamente. O aplicativo pode obter uma lista de nomes e/ou endereços de locais sugeridos de uma das seguintes formas:

Chamar GMSPlacesClient

Para obter uma lista nomes e/ou endereços de locais sugeridos, chame o método GMSPlacesClient autocompleteQuery:bounds:filter:callback: com os seguintes com os seguintes parâmetros:

  • Uma string autocompleteQuery contendo o texto digitado pelo usuário.
  • Um objeto GMSCoordinateBounds polarizando os resultados a uma área específica definida por limites de latitude e longitude.
  • Um GMSAutocompleteFilter restringindo os resultados a um tipo específico de local. Para obter todos os tipos, forneça um valor nulo. Os seguintes tipos de local são permitidos no filtro:

    • kGMSPlacesAutocompleteTypeFilterNoFilter – um filtro vazio. Todos os resultados são retornados.
    • kGMSPlacesAutocompleteTypeFilterGeocode – retorna apenas resultados de geocodificação, excluindo estabelecimentos. Use esta solicitação para obter resultados não ambíguos em casos em que o local especificado seja indeterminado.
    • kGMSPlacesAutocompleteTypeFilterAddress – retorna somente resultados de preenchimento automático com endereço preciso. Use este tipo quando sabe que o usuário está buscando um endereço completo.
    • kGMSPlacesAutocompleteTypeFilterEstablishment – retorna somente estabelecimentos.
    • kGMSPlacesAutocompleteTypeFilterRegion – retorna apenas locais que são de um dos seguintes tipos:

      • locality
      • sublocality
      • postal_code
      • country
      • administrative_area_level_1
      • administrative_area_level_2
    • kGMSPlacesAutocompleteTypeFilterCity – retorna apenas resultados que correspondam a locality ou administrative_area_level_3.

Para saber mais, acesse tipos de local.

Um método de retorno de chamada para tratar das sugestões retornadas.

Os exemplos de código abaixo mostram uma chamada simplificada de 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);
                          }
                        }];
}

Uma API invoca o método de retorno de chamada especificado, passando uma matriz de objetos GMSAutocompletePrediction.

Cada objeto GMSAutocompletePrediction contém as seguintes informações:

  • attributedFullText – o texto completo da sugestão, na forma de NSAttributedString. Por exemplo, "Sydney Opera House, Sydney, Nova Gales do Sul, Austrália". Toda faixa de texto que corresponde à interação do usuário tem um atributo kGMSAutocompleteMatchAttribute. Você pode usar este atributo para destacar o texto correspondente na consulta do usuário, por exemplo, como mostrado abaixo.
  • placeID – o ID de local do local sugerido. Um ID de local é um identificador textual que distingue um local dos outros. Para saber mais sobre IDs de local, acesse Visão geral sobre IDs de local.

O exemplo de código a seguir ilustra como destacar em negrito as partes do resultado que correspondem ao texto da consulta do usuário usando 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;
    

Usar o coletor

Se quiser criar seu próprio widget de preenchimento automático do zero, use GMSAutocompleteFetcher, que empacota o método autocompleteQuery em GMSPlacesClient. O coletor controla as solicitações, retornando resultados apenas para os textos de pesquisa inseridos mais recentemente. Ele não fornece elementos de IU.

Para implementar GMSAutocompleteFetcher, faça o seguinte:

  1. Implemente o protocolo GMSAutocompleteFetcherDelegate.
  2. Crie um objeto GMSAutocompleteFetcher.
  3. Chame sourceTextHasChanged no coletor enquanto o usuário digita.
  4. Gerencie sugestões e erros usando os métodos didAutcompleteWithPredictions e didFailAutocompleteWithError do protocolo.

O exemplo de código a seguir demonstra como usar o coletor para obter o dado inserido pelo usuário e exibir correspondências de local em uma visualização de texto. O recurso de selecionar um local foi omitido. FetcherSampleViewController deriva de UIViewController em 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

Configurar o GMSCoordinateBounds de preenchimento automático

Você pode fornecer um GMSCoordinateBounds ao recurso de preenchimento automático para orientar os preenchimentos fornecidos. Por exemplo, já você já tem um mapa Google no controlador de visualizações, pode usar os limites da janela de visualização atual para polarizar os resultados do preenchimento automático.

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

Limites de uso

Exibir atribuições no aplicativo

  • Se o aplicativo usa o serviço de preenchimento automático programaticamente a IU também precisa exibir uma atribuição “Tecnologia do Google” ou aparecer em um mapa com o logotipo da Google.
  • Se o aplicativo usa o widget de preenchimento automático, não é preciso fazer mais nada (a atribuição exigida é exibida por padrão).
  • Se você recuperar e exibir mais informações do local depois de obter um local por ID, será necessário exibir atribuições de terceiros também.

Para conhecer mais detalhes, leia a documentação sobre atribuições.

Como controlar o indicador de atividade de rede

Para controlar o indicador de atividade de rede na barra de status do aplicativo, é preciso implementar os métodos delegados opcionais corretos para a classe “autocomplete” que você está usando e ativar e desativar o indicador de rede por conta própria.

  • Para GMSAutocompleteViewController, você deve implementar os métodos delegados didRequestAutocompletePredictions: e didUpdateAutocompletePredictions:.
  • Para GMSAutocompleteResultsViewController, você deve implementar os métodos delegados didRequestAutocompletePredictionsForResultsController: e didUpdateAutocompletePredictionsForResultsController:.
  • Para GMSAutocompleteTableDataSource, você deve implementar os métodos delegados didRequestAutocompletePredictionsForTableDataSource: e didUpdateAutocompletePredictionsForTableDataSource:.

Ao implementar esses métodos e definir [UIApplication sharedApplication].networkActivityIndicatorVisible como YES e NO, respectivamente, a barra de status combinará corretamente com a IU de preenchimento automático.

Solução de problemas

Embora possam ocorrer diversos erros, geralmente a maioria deles que pode acontecer no aplicativo é causada por erros de configuração (por exemplo, uso da chave de API incorreta ou chave com configuração incorreta) ou de cota (cota excedida). Consulte Limites de uso para saber mais sobre cotas.

Os erros que podem ocorrer pelo uso dos widgets de preenchimento automático são retornados no método didFailAutocompleteWithError() dos diversos protocolos delegados. A propriedade code do objeto NSError fornecido é definida como um dos valores da enumeração de GMSPlacesErrorCode.

Enviar comentários sobre…