Modyfikowanie interfejsu użytkownika

Za pomocą pakietu Navigation SDK na iOS możesz modyfikować sposób korzystania z mapy przez użytkowników, określając, które z wbudowanych elementów sterujących interfejsu i elementów mają się pojawiać na mapie oraz jakie gesty są dozwolone. Możesz też zmienić wygląd interfejsu nawigacji. Wskazówki dotyczące dopuszczalnych modyfikacji interfejsu nawigacji znajdziesz na stronie z zasadami.

Elementy sterujące interfejsu mapy

Pakiet Navigation SDK udostępnia pewne wbudowane elementy sterujące interfejsu podobne do tych, które można znaleźć w aplikacji Mapy Google na iOS. Widoczność tych elementów sterujących możesz przełączać za pomocą klasy GMSUISettings. Zmiany wprowadzone w tej klasie są natychmiast odzwierciedlane na mapie.

Kompas

Pakiet Navigation SDK udostępnia grafikę kompasu, która w określonych okolicznościach i tylko wtedy, gdy jest włączona, pojawia się w prawym górnym rogu mapy. Gdy użytkownik kliknie kompas, kamera animuje powrót do pozycji z zerowym namiarem (orientacja domyślna), a kompas po chwili znika.

Jeśli nawigacja jest włączona, a tryb kamery jest ustawiony na „śledzenie”, kompas pozostaje widoczny, a kliknięcie go powoduje przełączenie między perspektywą pochyloną a widokiem z góry.

Aby uniknąć rozpraszania uwagi kierowcy, kompas pozostaje w tej samej pozycji, jeśli nagłówek (w trybie portretowym) rozszerza się i koliduje z domyślną pozycją kompasu. Jeśli dodasz dodatkowy niestandardowy element sterujący nagłówka lub widok akcesoriów nagłówka, kompas zostanie ukryty, aby uniknąć konfliktów interfejsu.

Kompas obsługuje tryby dzienny i nocny, a także tryb ciemny.

Kompas jest domyślnie włączony w wersji 11.0.0 i nowszych. Możesz wyłączyć kompas, ustawiając właściwość compassButton obiektu GMSUISettings na false.

Swift

mapView.settings.compassButton = false

Objective-C

mapView.settings.compassButton = NO;

Przycisk Moja lokalizacja

Przycisk Moja lokalizacja pojawia się w prawym dolnym rogu ekranu tylko wtedy, gdy przycisk lokalizacji jest włączony. Gdy użytkownik kliknie ten przycisk, kamera animuje widok, aby skupić się na bieżącej lokalizacji użytkownika, jeśli jest ona znana. Możesz włączyć przycisk, ustawiając właściwość myLocationButton elementu GMSUISettings na true.

Swift

mapView.settings.myLocationButton = true

Objective-C

mapView.settings.myLocationButton = YES;

Przycisk wyśrodkowania

Gdy nawigacja jest włączona, przycisk wyśrodkowania pojawia się, gdy użytkownik przewija widok mapy, i znika, gdy użytkownik kliknie, aby wyśrodkować mapę. Aby przycisk wyśrodkowania był widoczny, ustaw właściwość recenterButtonEnabled elementu GMSUISettings na true. Aby przycisk wyśrodkowania się nie wyświetlał, ustaw recenterButtonEnabled na false.

Swift

mapView.settings.isRecenterButtonEnabled = true

Objective-C

mapView.settings.recenterButtonEnabled = YES;

Akcesoria interfejsu mapy

Pakiet Navigation SDK udostępnia elementy interfejsu, które pojawiają się podczas nawigacji, podobnie jak w aplikacji Mapy Google na iOS. Możesz dostosować widoczność lub wygląd tych elementów sterujących, jak opisano w tej sekcji. Wprowadzone tu zmiany zostaną odzwierciedlone podczas następnego przejazdu użytkownika.

Podczas nawigacji u góry ekranu wyświetla się nagłówek nawigacji, a u dołu – stopka nawigacji. Nagłówek nawigacji pokazuje nazwę ulicy i kierunek następnego skrętu na trasie, a także kierunek kolejnego skrętu. W stopce nawigacji wyświetlany jest szacowany czas i odległość do miejsca docelowego, a także szacowany czas dotarcia.

Możesz przełączać widoczność nagłówka i stopki nawigacji oraz ustawiać ich kolory automatycznie za pomocą tych właściwości:

Poniższy przykładowy kod pokazuje, jak włączyć widoczność nagłówka i stopki, a następnie ustawić navigationHeaderPrimaryBackgroundColor na niebieski, a navigationHeaderSecondaryBackgroundColor na czerwony.

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

Możesz dostosować aplikację, zastępując widok nagłówka nawigacji dodatkowej własnym, dostosowanym widokiem akcesoriów. W tym celu utwórz widok, który implementuje protokół GMSNavigationAccessoryView. Ten protokół ma jedną wymaganą metodę: -heightForAccessoryViewConstrainedToSize:onMapView:. Otrzymasz maksymalny dostępny rozmiar widoku w danym mapView i musisz podać wysokość, której wymaga Twój widok.

Następnie możesz przekazać ten widok do mapView, wywołując setHeaderAccessoryView:. mapView animuje wszystkie bieżące widoki, a następnie animuje widok niestandardowy. Aby widok niestandardowy mógł się wyświetlać, nagłówek nawigacyjny musi być widoczny.

Aby usunąć widok akcesoriów niestandardowego nagłówka, przekaż nil do setHeaderAccessoryView:.

Jeśli widok musi zmienić rozmiar w dowolnym momencie, możesz wywołać funkcję invalidateLayoutForAccessoryView:, przekazując widok, który musi zmienić rozmiar.

Przykład

Poniższy przykładowy kod pokazuje widok niestandardowy, który implementuje protokół GMSNavigationAccessoryView. Ten widok niestandardowy jest następnie używany do ustawiania niestandardowego widoku akcesoriów nagłówka nawigacji.

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

Kolory nagłówka w trybie słabego oświetlenia

Pakiet Navigation SDK na iOS oblicza sugerowany tryb jasny na podstawie pory dnia i bieżącej lokalizacji urządzenia, a gdy sugerowany tryb się zmienia (np. o wschodzie lub zachodzie słońca), wywołuje metodę detektora GMSNavigatorListener.didChangeSuggestedLightingMode. Możesz programowo modyfikować działanie trybu słabego oświetlenia w następujący sposób:

Lista wskazówek dojazdu

W aplikacji możesz podawać szczegółowe wskazówki dojazdu. Poniższy przykład pokazuje, jak to zrobić. Te kroki mogą się różnić w zależności od implementacji.

  1. Włącz przycisk punktu wejścia po pomyślnym zakończeniu setDestinations w GMSNavigator (nawigator) i włączeniu guidanceActive w nawigatorze.
  2. Gdy użytkownik kliknie przycisk punktu wejścia, utwórz GMSNavigationDirectionsListController (kontroler) z nawigatorem powiązanym z GMSMapView (mapView).
  3. Dodaj kontroler do instancji UIViewController (kontroler widoku) i dodaj directionsListView jako podwidok kontrolera widoku. Metody reloadData i invalidateLayout kontrolera powinny być wywoływane tak samo jak w przypadku UICollectionView.
  4. Przenieś kontroler widoku do hierarchii kontrolerów widoku aplikacji.

Poniższy przykładowy kod pokazuje, jak dodać 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)
  // Make sure 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];
  // Make sure 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];
  ...
}

...

Pasek postępu przejazdu

Do nawigacji dodano pasek postępu przejazdu.

Pasek postępu przejazdu to pionowy pasek, który pojawia się po stronie początkowej/głównej mapy po rozpoczęciu nawigacji. Gdy ta opcja jest włączona, wyświetla się podsumowanie całego przejazdu wraz z miejscem docelowym i aktualną pozycją użytkownika.

Dzięki temu użytkownicy mogą przewidzieć nadchodzące problemy, takie jak korki, bez konieczności powiększania widoku. W razie potrzeby może on zmienić trasę przejazdu. Jeśli użytkownik zmieni trasę przejazdu, pasek postępu zostanie zresetowany, tak jakby od tego momentu rozpoczął się nowy przejazd.

Pasek postępu przejazdu wyświetla te wskaźniki stanu:

  • Stan ruchu – stan ruchu na trasie.

  • Current location (Bieżąca lokalizacja) – bieżąca lokalizacja kierowcy podczas przejazdu.

  • Przebyta trasa – przebyty odcinek trasy.

Włącz pasek postępu przejazdu, ustawiając właściwość navigationTripProgressBarEnabled w GMSUISettings.

Swift

mapView.settings.isNavigationTripProgressBarEnabled = true

Objective-C

mapView.settings.navigationTripProgressBarEnabled = YES;

Pozycjonowanie paska postępu przejazdu

  • Lewa strona paska jest mniej więcej wyrównana z lewą stroną prędkościomierza, logo Google i przycisku Wyśrodkuj (gdy jest widoczny). Szerokość wynosi 12 pt.
  • Pasek postępu przejazdu reaguje dynamicznie na przestrzeń pionową na ekranie. Dolna krawędź paska znajduje się 210 pt od dolnej krawędzi ekranu. Góra paska postępu przejazdu pozostaje w odległości co najmniej 170 pt od góry ekranu, a maksymalna wysokość paska wynosi 400 pt.
  • Jeśli pasek postępu przejazdu nakłada się na nagłówek nawigacji lub inne elementy interfejsu nawigacji, pojawia się pod tymi elementami.

Prompt Visibility API (eksperymentalny)

Interfejs Prompt Visibility API pozwala uniknąć konfliktów między elementami interfejsu generowanymi przez pakiet Navigation SDK a własnymi elementami interfejsu. W tym celu dodaje się detektor, który odbiera wywołanie zwrotne, zanim element interfejsu pakietu Navigation SDK ma się pojawić i zaraz po jego usunięciu. Więcej informacji, w tym przykładowy kod, znajdziesz w sekcji Prompt Visibility API na stronie Konfigurowanie zakłóceń w czasie rzeczywistym.

Sterowanie prędkościomierzem

Gdy nawigacja jest włączona, a tryb podróży jest ustawiony na jazdę samochodem, pakiet Navigation SDK na iOS wyświetla w dolnym rogu mapy element sterujący ograniczeniem prędkości, który pokazuje aktualne ograniczenie prędkości. Gdy kierowca przekroczy dozwoloną prędkość, element sterujący rozwinie się, aby wyświetlić drugi prędkościomierz z aktualną prędkością kierowcy.

Możesz ustawić poziomy alertów, aby zmienić formatowanie wyświetlania prędkościomierza, gdy kierowca przekroczy limit prędkości o określoną wartość. Możesz na przykład określić, że aktualna prędkość ma być wyświetlana czerwonym tekstem, gdy kierowca przekroczy ograniczenie prędkości o 5 mil na godzinę, i na czerwonym tle, gdy przekroczy ograniczenie prędkości o 10 mil na godzinę.

Aby wyświetlić element sterujący ograniczeniem prędkości, ustaw właściwość shouldDisplaySpeedometer obiektu GMSMapView na true. Aby wyłączyć wyświetlanie elementu sterującego ograniczeniem prędkości, ustaw shouldDisplaySpeedometer na false.

Swift

mapView.shouldDisplaySpeedometer = true

Objective-C

mapView.shouldDisplaySpeedometer = YES;

Więcej informacji o ustawianiu alertów prędkościomierza znajdziesz w artykule Konfigurowanie alertów prędkościomierza.

Znaczniki miejsc docelowych

Możesz wyświetlać lub ukrywać znaczniki miejsc docelowych na danej trasie, ustawiając właściwość showsDestinationMarkers obiektu GMSUISettings. W przykładzie poniżej pokazujemy, jak wyłączyć znaczniki miejsc docelowych.

Swift

mapView.settings.showsDestinationMarkers = false

Objective-C

mapView.settings.showsDestinationMarkers = NO;

Funkcje mapy

Pakiet Navigation SDK umożliwia dalsze dostosowywanie nawigacji dla użytkowników. Zmiany wprowadzone w instancji zostaną odzwierciedlone podczas następnej aktualizacji aplikacji przez użytkownika.

Wyróżnianie miejsc docelowych i wejść

Wyróżnianie miejsc docelowych i wejść

Gdy miejsce docelowe zostanie utworzone za pomocą placeID, budynek docelowy zostanie wyróżniony, a w miarę możliwości wyświetli się ikona wejścia. Te wskazówki wizualne pomagają użytkownikom odróżnić i znaleźć miejsce docelowe.

Aby utworzyć miejsce docelowe z obiektem placeID, użyj jednego z inicjatorów GMSNavigationWaypoint, które akceptują obiekt placeID. Na przykład miejsca docelowe utworzone w samouczku dotyczącym nawigacji po trasie zawierają wyróżnienie miejsca docelowego i etykiety wejścia, jeśli są dostępne.

Wyświetlanie budynków 3D podczas nawigacji

Wyświetlanie budynków 3D podczas nawigacji

Budynki 3D są domyślnie wyświetlane podczas nawigacji. Aby wyłączyć tę funkcję, ustaw właściwość buildingsEnabled na false (Swift) lub NO (Objective-C).

Wyłączanie domyślnych gestów na mapie

Domyślne gesty na mapie możesz wyłączyć, ustawiając właściwości klasy GMSUISettings, która jest dostępna jako właściwość klasy GMSMapView. Poniższe gesty można włączać i wyłączać programowo. Pamiętaj, że wyłączenie gestu nie ograniczy dostępu programowego do ustawień aparatu.

  • scrollGestures – określa, czy gesty przewijania są włączone czy wyłączone. Jeśli ta opcja jest włączona, użytkownicy mogą przesuwać palcem, aby przesuwać kamerę.
  • zoomGestures – określa, czy gesty powiększania są włączone czy wyłączone. Jeśli ta opcja jest włączona, użytkownicy mogą dwukrotnie kliknąć, kliknąć dwoma palcami lub rozciągnąć palce, aby powiększyć obraz z kamery. Pamiętaj, że dwukrotne kliknięcie lub ściągnięcie palców, gdy włączone są scrollGestures, może spowodować przesunięcie kamery do określonego punktu.
  • tiltGestures – określa, czy gesty przechylania są włączone czy wyłączone. Jeśli ta opcja jest włączona, użytkownicy mogą przechylać kamerę, przesuwając 2 palcami w dół lub w górę.
  • rotateGestures – określa, czy gesty obracania są włączone czy wyłączone. Jeśli ta opcja jest włączona, użytkownicy mogą obracać kamerę za pomocą gestu obracania dwoma palcami.

W tym przykładzie wyłączono gesty przesuwania i powiększania.

Swift

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

Objective-C

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

Elementy sterujące pozycją i elementy interfejsu

Możesz ustawić elementy sterujące i inne elementy interfejsu względem pozycji nagłówka i stopki nawigacji, używając tych właściwości:

  • navigationHeaderLayoutGuide
  • navigationFooterLayoutGuide
  • bottomTrailingButtonsLayoutGuide

Poniższy przykładowy kod pokazuje, jak użyć prowadnic układu do umieszczenia pary etykiet w widoku mapy:

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;

Przykład użycia elementu bottomTrailingButtonsLayoutGuide do pozycjonowania przycisku zgłaszania zakłóceń w czasie rzeczywistym znajdziesz w artykule Konfigurowanie zakłóceń w czasie rzeczywistym.

Ukrywanie tras alternatywnych

Gdy interfejs użytkownika jest przeładowany informacjami, możesz zmniejszyć ich ilość, wyświetlając mniej tras alternatywnych niż domyślne (2) lub nie wyświetlając ich wcale. Możesz skonfigurować tę opcję przed pobraniem tras, konfigurując GMSNavigationRoutingOptions i ustawiając alternateRoutesStrategy na jedną z tych wartości typu wyliczeniowego:

Wartość typu wyliczeniowegoOpis
GMSNavigationAlternateRoutesStrategyAll Domyślny: Wyświetla maksymalnie 2 trasy alternatywne.
GMSNavigationAlternateRoutesStrategyOne Wyświetla jedną trasę alternatywną (jeśli jest dostępna).
GMSNavigationAlternateRoutesStrategyNone Ukrywa alternatywne trasy.

Przykład

Poniższy przykładowy kod pokazuje, jak całkowicie ukryć trasy alternatywne.

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