Com o SDK do Navigation para iOS, você pode modificar a experiência do usuário com seu mapa determinando quais dos controles e elementos da interface integrados aparecem no mapa e quais gestos você permite. Você também pode modificar a aparência visual da interface de navegação. Consulte a página de políticas para diretrizes sobre modificações aceitáveis na interface de navegação.
Controles de interface do mapa
O SDK do Navigation fornece alguns controles de interface integrados semelhantes aos encontrados no app Google Maps para iOS. É possível
alternar a visibilidade desses controles usando a classe GMSUISettings
.
As alterações feitas nessa classe são aplicadas imediatamente ao mapa.
Bússola
O SDK do Navigation oferece um gráfico de bússola que aparece no canto superior direito do mapa em determinadas circunstâncias e apenas quando ativado. A bússola só é exibida quando a câmera está orientada com um rolamento diferente do norte exato (um rolamento diferente de zero). Quando o usuário clica na bússola, a câmera volta para uma posição com um rolamento 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 "Seguir", a bússola vai permanecer visível, e um toque na bússola alternará entre as perspectivas da câmera de visão geral e inclinada.
Por padrão, a bússola é desativada. Ative a bússola definindo a propriedade compassButton
de GMSUISettings
como true
. No entanto, não é possível forçar a exibição permanente dela.
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 está ativado. Quando um usuário clica no botão, a
câmera se move para focar no local atual do usuário, se essa
localização for conhecida. É 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 "Recentralizar" aparece quando o usuário rola a visualização do mapa e desaparece quando ele toca para recentralizar o mapa. Para permitir
que o botão "Recentralizar" apareça, defina a propriedade recenterButtonEnabled
de
GMSUISettings
como true
. Para evitar que o botão "Recentralizar" apareça, defina
recenterButtonEnabled
como false
.
Swift
mapView.settings.isRecenterButtonEnabled = true
Objective-C
mapView.settings.recenterButtonEnabled = YES;
Acessórios para interface de mapa
O SDK do 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 aparência desses controles, conforme descrito nesta seção. As mudanças feitas aqui são aplicadas na próxima viagem do usuário.
Cabeçalho e rodapé de navegação
Durante a navegação, o cabeçalho aparece na parte de cima da tela e o rodapé 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, bem como a direção da curva seguinte. O rodapé da navegação mostra o tempo e a distância estimados até o destino, bem como o horário previsto de chegada.
Você pode 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é da navegação está visível (o padrão étrue
).navigationHeaderPrimaryBackgroundColor
: define a cor principal do plano de fundo do cabeçalho de navegação.navigationHeaderSecondaryBackgroundColor
: define a cor de plano de fundo secundária do cabeçalho de navegação.
O exemplo de código a seguir mostra como ativar a visibilidade do cabeçalho e
rodapé e, em seguida, 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];
Visualização do cabeçalho do acessório de navegação
Você pode personalizar seu app substituindo a visualização do cabeçalho de navegação secundária
pela sua própria visualização de acessório personalizada. Para fazer 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 na mapView especificada e precisa informar a altura necessária para ela.
Você pode transmitir essa visualização ao mapView chamando setHeaderAccessoryView:
. O mapView anima todas as visualizações atuais e, em seguida, faz a animação na 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 do acessório de cabeçalho personalizado, transmita nil
para
setHeaderAccessoryView:
.
Se o tamanho da visualização precisar mudar a qualquer momento, chame
invalidateLayoutForAccessoryView:
, transmitindo a visualização que precisa mudar de
tamanho.
Exemplo
O exemplo de código abaixo demonstra uma visualização personalizada que implementa o
protocolo GMSNavigationAccessoryView
. Essa visualização personalizada é usada para definir uma
visualização de acessório do 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];
Lista de rotas
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 dependendo da sua implementação.
- Ative um botão de ponto de entrada depois que
setDestinations
noGMSNavigator
(navegador) for concluído eguidanceActive
no navegador tiver sido ativado. - Quando o usuário tocar no botão do ponto de entrada, crie um
GMSNavigationDirectionsListController
(controlador) com o navegador associado aoGMSMapView
(mapView
). - Adicione o controlador a uma instância de
UIViewController
(controlador de visualização) e adicione odirectionsListView
como uma subvisualização do controlador de visualização. Os métodosreloadData
einvalidateLayout
no controlador precisam ser chamados como faria comUICollectionView
. - Envie o controlador de visualização para a hierarquia do controlador de visualização do app.
O exemplo de código abaixo 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 é uma barra vertical que aparece na borda direita final do mapa quando a navegação é iniciada. Quando ativada, ela mostra uma visão geral de uma viagem inteira, com o destino e a posição atual do usuário.
Com ele, os usuários podem antecipar rapidamente problemas futuros, como tráfego, sem precisar aumentar o zoom. Ela pode redirecionar a viagem, se necessário. Se o usuário redirecionar a viagem, a barra de progresso será redefinida como se uma nova viagem tivesse começado desse ponto.
A barra de progresso da viagem exibe os seguintes indicadores de status:
Status do trânsito: o status do trânsito futuro.
Local atual: o local do motorista na viagem.
Trajeto decorrido: o trecho decorrido 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;
Semáforos e sinais de parada
É possível ativar semáforos e placas de parada no mapView
. Com
esse recurso, o usuário pode ativar a exibição de semáforos ou ícones de placa de parada
ao longo do trajeto, fornecendo um contexto melhor para viagens mais eficientes e
precisas.
Por padrão, semáforos e sinais de parada ficam 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 carro, o SDK do Navigation para iOS mostra um controle de limite de velocidade na parte de baixo do mapa, mostrando 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.
Você pode definir níveis de alerta para mudar a formatação da tela do velocímetro quando o motorista excede o limite de velocidade em um valor especificado. Por exemplo, você pode especificar que a velocidade atual apareça com uma cor de texto vermelha quando o motorista exceder o limite de velocidade em 8 km/h e com uma cor de fundo vermelha quando o motorista exceder o limite em 16 km/h.
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 saber mais sobre como definir alertas para o velocímetro, consulte Configurar alertas do velocímetro.
Marcadores de destino
Você pode mostrar ou ocultar os marcadores de destino de um determinado trajeto definindo a propriedade showsDestinationMarkers
de GMSUISettings
. O exemplo a seguir mostra a desativação dos marcadores de destino.
Swift
mapView.settings.showsDestinationMarkers = false
Objective-C
mapView.settings.showsDestinationMarkers = NO;
Recursos da experiência no mapa
O SDK do Navigation permite fazer mais personalizações na experiência de navegação dos seus usuários. As alterações feitas na instância serão refletidas na próxima atualização do app pelo usuário.
Desativar gestos de mapa padrão
Para desativar os gestos padrão, defina propriedades da classe GMSUISettings
, que está disponível como uma propriedade do GMSMapView
.
Os gestos a seguir podem ser ativados e desativados programaticamente. Desativar o 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 ficam ativados ou desativados. Se ativado, os usuários podem tocar duas vezes, tocar com dois dedos ou fazer gesto de pinça para aplicar o zoom na câmera. Tocar ou fazer gesto de pinça duplos quandoscrollGestures
estiver ativado pode movimentar a câmera até o ponto especificado.tiltGestures
: controla se os gestos de inclinação ficam ativados ou desativados. Se ativado, os usuários podem deslizar com dois dedos para baixo ou para cima para inclinar a câmera.rotateGestures
: controla se os gestos de rotação ficam 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
Você pode 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
O exemplo de código a seguir mostra o uso dos guias de layout para posicionar dois rótulos na visualização de 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;
Ocultar trajetos alternativos
Quando a interface do usuário fica sobrecarregada com muita informação, é possível reduzir a sobrecarga exibindo menos rotas alternativas do que o padrão (duas) ou não exibindo rotas alternativas. É possível definir essa opção antes
de buscar as rotas configurando GMSNavigationRoutingOptions
e definindo
alternateRoutesStrategy
com um dos seguintes valores de enumeração:
Valor de enumeração | Descrição |
---|---|
GMSNavigationAlternateRoutesStrategyAll | Padrão. Mostra até duas rotas alternativas. |
GMSNavigationAlternateRoutesStrategyOne | Mostra um trajeto alternativo (se houver). |
GMSNavigationAlternateRoutesStrategyNone | Oculta rotas alternativas. |
Exemplo
O exemplo de código a seguir demonstra como ocultar todas as 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){...}];