Modificar a IU de navegação

Com o SDK Navigation para iOS, você pode modificar a experiência do usuário com seu mapa determinando quais elementos e controles integrados da interface aparecem no mapa e quais gestos são permitidos. Também é possível modificar a aparência visual da interface de navegação. Consulte a página de políticas para ver diretrizes sobre modificações aceitáveis na interface de navegação.

Controles da interface do mapa

O SDK Navigation oferece alguns controles de IU integrados semelhantes aos encontrados no app Google Maps para iOS. É possível alternar a visibilidade desses controles usando a classe GMSUISettings. As mudanças feitas nessa classe são aplicadas imediatamente ao mapa.

Bússola

O SDK de navegação fornece um gráfico de bússola que aparece no canto superior direito do mapa em determinadas circunstâncias e somente quando ativado. Quando o usuário clica na bússola, a câmera volta para uma posição com direção zero (orientação padrão), e a bússola desaparece pouco tempo depois.

Se a navegação estiver ativada e o modo de câmera estiver definido como "seguindo", a bússola vai permanecer visível e tocar nela alternará entre as perspectivas de câmera inclinada e de visão geral.

Para evitar distrações do motorista, a bússola permanece na mesma posição se o cabeçalho (no modo retrato) se expandir e entrar em conflito com a posição padrão da bússola. Se você adicionar um controle personalizado ou uma visualização de acessório de cabeçalho secundário, a bússola será oculta para evitar conflitos na interface.

A bússola oferece suporte aos modos diurno e noturno, além do modo escuro.

Por padrão, a bússola é desativada. Para ativar a bússola, defina a propriedade compassButton de GMSUISettings como true. No entanto, não é possível forçar a exibição permanente da bússola.

Swift

mapView.settings.compassButton = true

Objective-C

mapView.settings.compassButton = YES;

Botão "Meu local"

O botão "Meu local" aparece no canto inferior direito da tela somente quando ele está ativado. Quando um usuário clica no botão, a câmera é animada para focar no local atual do usuário, se ele for conhecido. É possível ativar o botão definindo a propriedade myLocationButton de GMSUISettings como true.

Swift

mapView.settings.myLocationButton = true

Objective-C

mapView.settings.myLocationButton = YES;

Botão "Recentralizar"

Quando a navegação está ativada, o botão de recentralização aparece quando o usuário rola a visualização do mapa e desaparece quando o usuário toca para recentralizar o mapa. Para permitir que o botão de recentração apareça, defina a propriedade recenterButtonEnabled de GMSUISettings como true. Para impedir que o botão de recentização apareça, defina recenterButtonEnabled como false.

Swift

mapView.settings.isRecenterButtonEnabled = true

Objective-C

mapView.settings.recenterButtonEnabled = YES;

Acessórios da interface do mapa

O SDK Navigation oferece acessórios de interface que aparecem durante a navegação, semelhantes aos encontrados no app Google Maps para iOS. É possível ajustar a visibilidade ou a aparência desses controles, conforme descrito nesta seção. As mudanças feitas aqui são refletidas na próxima viagem do usuário.

Durante a navegação, o cabeçalho de navegação aparece na parte de cima da tela e o rodapé de navegação aparece na parte de baixo. O cabeçalho de navegação mostra o nome da rua e a direção da próxima curva no trajeto, além da direção da curva seguinte. O rodapé de navegação mostra o tempo estimado e a distância até o destino, além do horário estimado de chegada.

É possível alternar a visibilidade do cabeçalho e do rodapé de navegação e definir as cores de maneira programática usando as seguintes propriedades:

  • navigationHeaderEnabled: controla se o cabeçalho de navegação está visível (o padrão é true).
  • navigationFooterEnabled: controla se o rodapé de navegação está visível (o padrão é true).
  • navigationHeaderPrimaryBackgroundColor: define a cor de plano de fundo principal para o cabeçalho de navegação.
  • navigationHeaderSecondaryBackgroundColor: define a cor de plano de fundo secundária para o cabeçalho de navegação.

O exemplo de código a seguir mostra como ativar a visibilidade do cabeçalho e do rodapé, definir navigationHeaderPrimaryBackgroundColor como azul e navigationHeaderSecondaryBackgroundColor como vermelho.

Swift

mapView.settings.isNavigationHeaderEnabled = true
mapView.settings.isNavigationFooterEnabled = true
mapView.settings.navigationHeaderPrimaryBackgroundColor = .blue
mapView.settings.navigationHeaderSecondaryBackgroundColor = .red

Objective-C

mapView.settings.navigationHeaderEnabled = YES;
mapView.settings.navigationFooterEnabled = YES;
mapView.settings.navigationHeaderPrimaryBackgroundColor = [UIColor blueColor];
mapView.settings.navigationHeaderSecondaryBackgroundColor = [UIColor redColor];

Você pode personalizar seu app substituindo a visualização de cabeçalho de navegação secundária pela sua própria visualização de acessório personalizada. Para isso, crie uma visualização que implemente o protocolo GMSNavigationAccessoryView. Esse protocolo tem um método obrigatório: -heightForAccessoryViewConstrainedToSize:onMapView:. Você recebe o tamanho máximo disponível para sua visualização no mapView fornecido e precisa informar a altura necessária.

Em seguida, transmita essa visualização para o mapView chamando setHeaderAccessoryView:. O mapView anima as visualizações atuais e, em seguida, anima sua visualização personalizada. O cabeçalho de navegação precisa estar visível para que a visualização personalizada seja exibida.

Para remover a visualização de acessório de cabeçalho personalizado, transmita nil para setHeaderAccessoryView:.

Se a visualização precisar mudar de tamanho a qualquer momento, chame invalidateLayoutForAccessoryView:, transmitindo a visualização que precisa mudar de tamanho.

Exemplo

O exemplo de código a seguir demonstra uma visualização personalizada que implementa o protocolo GMSNavigationAccessoryView. Essa visualização personalizada é usada para definir uma visualização de acessório de cabeçalho de navegação personalizada.

Swift

class MyCustomView: UIView, GMSNavigationAccessoryView {

  func heightForAccessoryViewConstrained(to size: CGSize, on mapView: GMSMapView) -> CGFloat {
    // viewHeight gets calculated as the height your view needs.
    return viewHeight
  }

}

let customView = MyCustomView(...)
mapView.setHeaderAccessory(customView)

// At some later point customView changes size.
mapView.invalidateLayout(forAccessoryView: customView)

// Remove the custom header accessory view.
mapView.setHeaderAccessory(nil)

Objective-C

@interface MyCustomView : UIView <GMSNavigationAccessoryView>

@end

@implementation MyCustomView

- (CGFloat)heightForAccessoryViewConstrainedToSize:(CGSize)size onMapView:(GMSMapView *)mapView {
  // viewHeight gets calculated as the height your view needs.
  return viewHeight;
}

@end

MyCustomView *customView = [[MyCustomView alloc] init];
[_mapView setHeaderAccessoryView:customView];

// At some later point customView changes size.
[_mapView invalidateLayoutForAccessoryView:customView];

// Remove the custom header accessory view.
[_mapView setHeaderAccessoryView:nil];

Modo noturno

O método do listener GMSNavigatorListener.didChangeSuggestedLightingMode é acionado quando as condições de iluminação estimadas são atualizadas, por exemplo, quando anoitece no local atual do dispositivo. É possível modificar o comportamento do modo noturno de maneira programática das seguintes maneiras:

Lista de direções

Você pode fornecer instruções detalhadas no seu app. O exemplo a seguir mostra uma maneira possível de fazer isso. Essas etapas podem variar de acordo com sua implementação.

  1. Ative um botão de ponto de entrada depois que setDestinations no GMSNavigator (navegador) for concluído e guidanceActive no navegador for ativado.
  2. Quando um usuário tocar no botão de ponto de entrada, crie um GMSNavigationDirectionsListController (controlador) com o navegador associado ao GMSMapView (mapView).
  3. Adicione o controlador a uma instância de UIViewController (controlador de visualização) e adicione o directionsListView como uma subvisualização do controlador de visualização. Os métodos reloadData e invalidateLayout no controlador precisam ser chamados como um UICollectionView.
  4. Empurre o controlador de visualização para a hierarquia de controladores de visualização do app.

O exemplo de código a seguir mostra como adicionar um DirectionsListViewController.

Swift

override func viewDidLoad() {
  super.viewDidLoad()
  // Add the directionsListView to the host view controller's view.
  let directionsListView = directionsListController.directionsListView
  directionsListView.frame = self.view.frame
  self.view.addSubview(directionsListView)
  directionsListView.translatesAutoresizingMaskIntoConstraints = false
  directionsListView.topAnchor.constraint(equalTo: self.view.topAnchor).isActive = true
  directionsListView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor).isActive = true
  directionsListView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor).isActive = true
  directionsListView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor).isActive = true
  ...
}

override func viewWillAppear(_ animated: Bool) {
  super.viewWillAppear(animated)
  // Ensure data is fresh when the view appears.
  directionsListController.reloadData()
  ...
}

override func willTransition(to newCollection: UITraitCollection, with coordinator: UIViewControllerTransitionCoordinator) {
  super.willTransition(to: newCollection, with: coordinator)
  // Invalidate the layout during rotation.
  coordinator.animate(alongsideTransition: {_ in
    self.directionsListController.invalidateLayout()
  })
  ...
}

Objective-C

- (void)viewDidLoad {
  [super viewDidLoad];
  // Add the directionsListView to the host view controller's view.
  UIView *directionsListView = _directionsListController.directionsListView;
  directionsListView.frame = self.view.bounds;
  [self.view addSubview:directionsListView];
  directionsListView.translatesAutoresizingMaskIntoConstraints = NO;
  [directionsListView.topAnchor constraintEqualToAnchor:self.view.topAnchor].active = YES;
  [directionsListView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor].active = YES;
  [directionsListView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor].active = YES;
  [directionsListView.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor].active = YES;
  ...
}

- (void)viewWillAppear:(BOOL)animated {
  [super viewWillAppear:animated];
  // Ensure data is fresh when the view appears.
  [_directionsListController reloadData];
  ...
}

- (void)willTransitionToTraitCollection:(UITraitCollection *)newCollection
              withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
  [super willTransitionToTraitCollection:newCollection withTransitionCoordinator:coordinator];
  void(^animationBlock)(id <UIViewControllerTransitionCoordinatorContext>context) =
      ^void(id <UIViewControllerTransitionCoordinatorContext>context) {
    [_directionsListController invalidateLayout];
  };
  // Invalidate the layout during rotation.
  [coordinator animateAlongsideTransition:animationBlock
                               completion:nil];
  ...
}

...

Barra de progresso da viagem

A barra de progresso da viagem foi adicionada à navegação.

A barra de progresso da viagem é uma barra vertical que aparece no lado inicial/principal do mapa quando a navegação começa. Quando ativado, ele mostra uma visão geral de uma viagem inteira, junto com o destino e a posição atual do usuário.

Isso permite que os usuários antecipem rapidamente qualquer problema futuro, como o tráfego, sem precisar dar zoom. O motorista pode mudar a rota da viagem, se necessário. Se o usuário mudar o trajeto, a barra de progresso será redefinida como se uma nova viagem tivesse começado a partir desse ponto.

A barra de progresso da viagem mostra os seguintes indicadores de status:

  • Status do trânsito: o status do trânsito que está por vir.

  • Localização atual: a localização do motorista na viagem.

  • Tempo da rota: o tempo da viagem.

Ative a barra de progresso da viagem definindo a propriedade navigationTripProgressBarEnabled em GMSUISettings.

Swift

mapView.settings.isNavigationTripProgressBarEnabled = true

Objective-C

mapView.settings.navigationTripProgressBarEnabled = YES;

Posicionamento da barra de progresso da viagem

  • O lado esquerdo da barra se alinha aproximadamente com a esquerda do velocímetro, o logotipo do Google e o botão "Recentralizar" (quando visível). A largura é de 12 pontos.
  • A barra de progresso da viagem responde dinamicamente ao espaço vertical na tela. A parte de baixo da barra está posicionada a 210 pt da parte de baixo da tela. A parte de cima da barra de progresso da viagem fica a pelo menos 170 pontos da parte de cima da tela, com uma altura máxima de 400 pontos.
  • Se a barra de progresso da viagem se sobrepor ao card de direção ou a outros elementos da IU de navegação, ela vai aparecer abaixo desses elementos.

API Prompt Visibility (experimental)

A API Prompt Visibility permite evitar conflitos entre elementos de interface gerados pelo SDK de navegação e seus próprios elementos de interface personalizados, adicionando um listener para receber um callback antes que um elemento de interface do SDK de navegação esteja prestes a aparecer e assim que o elemento for removido. Para mais informações, incluindo exemplos de código, consulte a seção API Prompt Visibility da página Configurar interrupções em tempo real.

Semáforos e placas de pare

Placas de pare e semáforos mostrados durante a navegação.

É possível ativar a exibição de semáforos e sinais de parada durante a navegação ativa no mapView, que fornece mais contexto para rotas e manobras de viagem.

Por padrão, os semáforos e sinais de parada estão desativados no SDK do Navigation para iOS. Para ativar esse recurso, chame as configurações GMSMapView para cada opção de forma independente: showsTrafficLights e showsStopSigns.


Swift

mapView.settings.showsTrafficLights = true
mapView.settings.showsStopSigns = true

Objective-C

mapView.settings.showsTrafficLights = YES;
mapView.settings.showsStopSigns = YES;

Controle do velocímetro

Quando a navegação está ativada e o modo de viagem está definido como "Dirigir", o SDK de navegação para iOS mostra um controle de limite de velocidade no canto inferior do mapa que mostra o limite de velocidade atual. Quando o motorista excede o limite de velocidade, o controle se expande para mostrar um segundo velocímetro com a velocidade atual do motorista.

É possível definir níveis de alerta para mudar a formatação da tela do velocímetro quando o motorista exceder o limite de velocidade em um valor especificado. Por exemplo, é possível especificar que a velocidade atual é exibida com uma cor de texto vermelha quando o motorista excede o limite de velocidade em 5 mph e com uma cor de plano de fundo vermelha quando o motorista excede o limite de velocidade em 10 mph.

Para mostrar o controle de limite de velocidade, defina a propriedade shouldDisplaySpeedometer de GMSUISettings como true. Para desativar a exibição do controle de limite de velocidade, defina shouldDisplaySpeedometer como false.

Swift

mapView.shouldDisplaySpeedometer = true

Objective-C

mapView.shouldDisplaySpeedometer = YES;

Para mais informações sobre como definir alertas para o velocímetro, consulte Configurar alertas do velocímetro.

Marcadores de destino

É possível mostrar ou ocultar os marcadores de destino de uma determinada rota definindo a propriedade showsDestinationMarkers de GMSUISettings. O exemplo a seguir mostra como desativar os marcadores de destino.

Swift

mapView.settings.showsDestinationMarkers = false

Objective-C

mapView.settings.showsDestinationMarkers = NO;

Recursos da experiência do mapa

O SDK de navegação permite fazer outras personalizações na experiência de navegação dos usuários. As mudanças feitas na instância são refletidas na próxima atualização do app do usuário.

Destaque e entradas do destino

Destino e entradas.

Quando um destino é criado com um placeID, o edifício de destino é destacado e um ícone de entrada é mostrado sempre que possível. Essas dicas visuais ajudam os usuários a distinguir e navegar até o destino pretendido.

Para criar um destino com um placeID, use um dos inicializadores GMSNavigationWaypoint que aceita um placeID. Por exemplo, os destinos criados no tutorial de navegação de uma rota incluem destaque de destino e rótulos de entrada quando disponíveis.

Desativar os gestos padrão do mapa

É possível desativar os gestos padrão no mapa definindo propriedades da classe GMSUISettings, que está disponível como uma propriedade de GMSMapView. Os gestos a seguir podem ser ativados e desativados programaticamente. A desativação do gesto não limita o acesso programático às configurações da câmera.

  • scrollGestures: controla se os gestos de rolagem estão ativados ou desativados. Se ativados, os usuários podem deslizar o dedo para deslocar a câmera.
  • zoomGestures: controla se os gestos de zoom estão ativados ou desativados. Se ativado, os usuários podem tocar duas vezes, tocar com dois dedos ou fazer pinça para ampliar a câmera. Toque duplo ou gesto de pinça quando scrollGestures estiver ativado pode mover a câmera para o ponto especificado.
  • tiltGestures: controla se os gestos de inclinação estão ativados ou desativados. Se ativado, os usuários podem usar um gesto de deslizar para cima ou para baixo com dois dedos para inclinar a câmera.
  • rotateGestures: controla se os gestos de rotação estão ativados ou desativados. Se ativado, os usuários podem usar um gesto de rotação com dois dedos para girar a câmera.

Neste exemplo, os gestos de movimentação e zoom foram desativados.

Swift

mapView.settings.scrollGestures = false
mapView.settings.zoomGestures = false

Objective-C

mapView.settings.scrollGestures = NO;
mapView.settings.zoomGestures = NO;

Posicionar controles e elementos da interface

É possível posicionar controles e outros elementos da interface em relação à posição do cabeçalho e do rodapé de navegação usando as seguintes propriedades:

  • navigationHeaderLayoutGuide
  • navigationFooterLayoutGuide
  • bottomTrailingButtonsLayoutGuide

O exemplo de código a seguir mostra como usar as guias de layout para posicionar um par de rótulos na visualização do mapa:

Swift

/* Add a label to the top left, positioned below the header. */
let topLabel = UILabel()
topLabel.text = "Top Left"
mapView.addSubview(topLabel)
topLabel.translatesAutoresizingMaskIntoConstraints = false
topLabel.topAnchor.constraint(equalTo: mapView.navigationHeaderLayoutGuide.bottomAnchor).isActive = true
topLabel.leadingAnchor.constraint(equalTo: mapView.leadingAnchor).isActive = true

/* Add a label to the bottom right, positioned above the footer. */
let bottomLabel = UILabel()
bottomLabel.text = "Bottom Right"
mapView.addSubview(bottomLabel)
bottomLabel.translatesAutoresizingMaskIntoConstraints = false
bottomLabel.bottomAnchor.constraint(equalTo: mapView.navigationFooterLayoutGuide.topAnchor).isActive = true
bottomLabel.trailingAnchor.constraint(equalTo: mapView.trailingAnchor).isActive = true

Objective-C

/* Add a label to the top left, positioned below the header. */
UILabel *topLabel = [[UILabel alloc] init];
topLabel.text = @"Top Left";
[view addSubview:topLabel];
topLabel.translatesAutoresizingMaskIntoConstraints = NO;
[topLabel.topAnchor
    constraintEqualToAnchor:mapView.navigationHeaderLayoutGuide.bottomAnchor].active = YES;
[topLabel.leadingAnchor constraintEqualToAnchor:mapView.leadingAnchor].active = YES;

/* Add a label to the bottom right, positioned above the footer. */
UILabel *bottomLabel = [[UILabel alloc] init];
bottomLabel.text = @"Bottom Right";
[view addSubview:bottomLabel];
bottomLabel.translatesAutoresizingMaskIntoConstraints = NO;
[bottomLabel.bottomAnchor
    constraintEqualToAnchor:mapView.navigationFooterLayoutGuide.topAnchor].active = YES;
[bottomLabel.trailingAnchor constraintEqualToAnchor:mapView.trailingAnchor].active = YES;

Para conferir um exemplo de como usar um bottomTrailingButtonsLayoutGuide para posicionar o botão de denúncia de interrupções em tempo real, consulte Configurar interrupções em tempo real.

Ocultar rotas alternativas

Quando a interface do usuário fica sobrecarregada com muitas informações, é possível reduzir a desordem mostrando menos rotas alternativas do que o padrão (duas) ou não mostrando nenhuma rota alternativa. É possível configurar essa opção antes de buscar as rotas definindo GMSNavigationRoutingOptions e alternateRoutesStrategy com um dos seguintes valores de enumeração:

Valor de enumeraçãoDescrição
GMSNavigationAlternateRoutesStrategyAll Padrão. Mostra até duas rotas alternativas.
GMSNavigationAlternateRoutesStrategyOne Mostra uma rota alternativa (se disponível).
GMSNavigationAlternateRoutesStrategyNone Oculta as rotas alternativas.

Exemplo

O exemplo de código abaixo demonstra como ocultar rotas alternativas.

Swift

let routingOptions = GMSNavigationRoutingOptions(alternateRoutesStrategy: .none)
navigator?.setDestinations(destinations,
                           routingOptions: routingOptions) { routeStatus in
  ...
}

Objective-C

GMSNavigationRoutingOptions *routingOptions = [[GMSNavigationRoutingOptions alloc] initWithAlternateRoutesStrategy:GMSNavigationAlternateRoutesStrategyNone];
[navigator setDestinations:destinations
            routingOptions:routingOptions
                  callback:^(GMSRouteStatus routeStatus){...}];