Navigation SDK for Android を使用すると、地図に表示する組み込みの UI コントロールと要素を指定することで、地図のユーザー エクスペリエンスを変更できます。ナビゲーション UI の外観を調整することもできます。ナビゲーション UI で許可される変更に関するガイドラインについては、ポリシー ページをご覧ください。
このドキュメントでは、次の 2 つの方法で地図のユーザー インターフェースを変更する方法について説明します。
地図の UI コントロール
ナビゲーション ビューにカスタム UI 要素を配置して適切に配置するには、地図 UI コントロールを使用することをおすすめします。組み込みのレイアウトが変更されると、Navigation SDK for Android はカスタム コントロールの位置を自動的に変更します。位置ごとに一度に 1 つのカスタム コントロール ビューを設定できます。設計で複数の UI 要素が必要な場合は、それらを ViewGroup
に配置して setCustomControl
メソッドに渡すことができます。
setCustomControl
メソッドは、CustomControlPosition
列挙型で定義されている位置を提供します。
SECONDARY_HEADER
(ポートレート モードでのみ表示)BOTTOM_START_BELOW
BOTTOM_END_BELOW
FOOTER


カスタム コントロールを追加する
- カスタム UI 要素または ViewGroup を使用して Android View を作成します。
- XML をインフレートするか、カスタムビューをインスタンス化して、ビューのインスタンスを取得します。
CustomControlPosition
列挙型から選択したカスタム コントロールの位置を指定して、NavigationView.setCustomControl
またはSupportNavigationFragment.setCustomControl
を使用します。次の例では、フラグメントを作成し、セカンダリ ヘッダーの位置にカスタム コントロールを追加します。
mNavFragment.setCustomControl(getLayoutInflater(). inflate(R.layout.your_custom_control, null), CustomControlPosition.SECONDARY_HEADER); ```
カスタム コントロールを削除する
カスタム コントロールを削除するには、null
ビュー パラメータと選択したカスタム コントロールの位置を指定して setCustomControl
メソッドを呼び出します。
たとえば、次のスニペットは、カスタム セカンダリ ヘッダーを削除してデフォルト コンテンツに戻します。
mNavFragment.setCustomControl(null, CustomControlPosition.SECONDARY_HEADER);
カスタム コントロールの位置
Secondary header

このカスタム コントロールの位置を使用するには、位置 CustomControlPosition.SECONDARY_HEADER
を setCustomControl
に渡します。
デフォルトでは、ナビゲーション モードの画面レイアウトには、プライマリ ヘッダーの下にセカンダリ ヘッダーを配置するための位置が用意されています。このセカンダリ ヘッダーは、車線案内など、必要に応じて表示されます。アプリでは、このレイアウトのセカンダリ ヘッダー位置をカスタム コンテンツに使用できます。この機能を使用すると、デフォルトのセカンダリ ヘッダー コンテンツが制御対象になります。ナビゲーション ビューに背景がある場合、その背景はそのまま残り、セカンダリ ヘッダーで覆われます。アプリでカスタム コントロールを削除すると、その場所にデフォルトのセカンダリ ヘッダーが表示されることがあります。
カスタム セカンダリ ヘッダーの位置は、上端がプライマリ ヘッダーの下端と揃います。この位置は portrait mode
でのみサポートされています。landscape mode
では、セカンダリ ヘッダーを使用できず、レイアウトは変更されません。
ボトムスタート


このカスタム コントロールの位置を使用するには、位置 CustomControlPosition.BOTTOM_START_BELOW
を setCustomControl
に渡します。
このカスタム コントロールの位置は、地図の左下にあります。portrait mode
と landscape mode
の両方で、ETA カードまたはカスタム フッターの上に配置されます(どちらも存在しない場合は地図の下部に配置されます)。また、カスタム コントロール ビューの高さに合わせて、再中央ボタンや Google ロゴなどの Nav SDK 要素が上に移動します。このコントロールは、表示される地図の境界内に配置されるため、地図の下端または左端に追加されたパディングによって、このコントロールの位置も変更されます。
下端


このカスタム コントロールの位置を使用するには、位置 CustomControlPosition.BOTTOM_END_BELOW
を setCustomControl
に渡します。
このカスタム コントロールの位置は、地図の下端の隅にあります。portrait mode
では、到着予定時刻カードまたはカスタム フッターの上に配置されます(どちらもない場合、地図の下部に配置されます)。landscape mode
では、地図の下部に配置されます。端側(LTR の場合は右側)に表示される Nav SDK 要素は、カスタム コントロール ビューの高さに合わせて上に移動します。このコントロールは、表示される地図の境界内に配置されるため、地図の下端または端に追加されたパディングによって、このコントロールの位置も変更されます。
フッター


このカスタム コントロールの位置を使用するには、位置 CustomControlPosition.FOOTER
を setCustomControl
に渡します。
このカスタム コントロールの位置は、カスタム フッタービュー用に設計されています。Nav SDK の到着予定時刻カードが表示されている場合、このコントロールはその上に表示されます。指定しない場合、コントロールは地図の下端に配置されます。BOTTOM_START_BELOW
カスタム コントロールと BOTTOM_END_BELOW
カスタム コントロールとは異なり、このコントロールは表示される地図の境界外に配置されます。つまり、地図に追加されたパディングによってこのコントロールの位置が変更されることはありません。
portrait mode
では、カスタム フッターはフル幅です。CustomControlPosition.BOTTOM_START_BELOW
と CustomControlPosition.BOTTOM_END_BELOW
の両方の位置にあるカスタム コントロールと、Nav SDK UI 要素(再中央ボタンや Google ロゴなど)は、カスタム コントロールのフッターの上に配置されます。chevron のデフォルトの位置は、カスタム フッターの高さを考慮して設定されます。
landscape mode
では、カスタム フッターは Nav SDK の ETA カードと同様に半分の幅で、開始側(LTR の場合は左側)に配置されます。CustomControlPosition.BOTTOM_START_BELOW
位置のカスタム コントロールと、再中央ボタンや Google ロゴなどの Nav SDK UI 要素は、カスタム コントロールのフッターの上に配置されます。CustomControlPosition.BOTTOM_END_BELOW
位置のカスタム コントロールと、端(LTR の場合は右側)に沿った Nav SDK UI 要素は、地図の下端に沿って配置されます。カスタム フッターが存在する場合、フッターは地図の端まで拡張されないため、矢印のデフォルトの位置は変わりません。
CustomControlPosition.BOTTOM_START_BELOW
と CustomControlPosition.BOTTOM_END_BELOW
の位置にあるカスタム コントロールと、Nav SDK UI 要素(再中央ボタンや Google ロゴなど)は、カスタム コントロールのフッターの上に配置されます。
地図 UI アクセサリ
Navigation SDK for Android には、ナビゲーション中に表示される UI アクセサリが用意されています。これは、Android 版 Google マップ アプリに表示される UI アクセサリに似ています。これらのコントロールの表示または外観は、このセクションで説明するように調整できます。ここで行った変更は、次のナビゲーション セッション中に反映されます。
ナビゲーション UI で許可される変更に関するガイドラインについては、ポリシー ページをご覧ください。
コードを表示する
ナビゲーション アクティビティの Java コードを表示または非表示にする
package com.example.navsdkcustomization; import android.content.pm.PackageManager; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.Bundle; import android.util.Log; import android.widget.Toast; import androidx.annotation.NonNull; import androidx.appcompat.app.AppCompatActivity; import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat; import com.google.android.gms.maps.GoogleMap; import com.google.android.gms.maps.GoogleMap.CameraPerspective; import com.google.android.gms.maps.OnMapReadyCallback; import com.google.android.gms.maps.model.BitmapDescriptorFactory; import com.google.android.gms.maps.model.LatLng; import com.google.android.gms.maps.model.Marker; import com.google.android.gms.maps.model.MarkerOptions; import com.google.android.libraries.navigation.ListenableResultFuture; import com.google.android.libraries.navigation.NavigationApi; import com.google.android.libraries.navigation.Navigator; import com.google.android.libraries.navigation.SimulationOptions; import com.google.android.libraries.navigation.StylingOptions; import com.google.android.libraries.navigation.SupportNavigationFragment; import com.google.android.libraries.navigation.Waypoint; /** An activity that displays a map and a customized navigation UI. */ public class NavigationActivityCustomization extends AppCompatActivity { private static final String TAG = NavigationActivityCustomization.class.getSimpleName(); private Navigator mNavigator; private SupportNavigationFragment mNavFragment; private GoogleMap mMap; // Define the Sydney Opera House by specifying its place ID. private static final String SYDNEY_OPERA_HOUSE = "ChIJ3S-JXmauEmsRUcIaWtf4MzE"; // Set fields for requesting location permission. private static final int PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION = 1; private boolean mLocationPermissionGranted; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // Initialize the Navigation SDK. initializeNavigationSdk(); } /** * Starts the Navigation SDK and sets the camera to follow the device's location. Calls the * navigateToPlace() method when the navigator is ready. */ private void initializeNavigationSdk() { /* * Request location permission, so that we can get the location of the * device. The result of the permission request is handled by a callback, * onRequestPermissionsResult. */ if (ContextCompat.checkSelfPermission( this.getApplicationContext(), android.Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) { mLocationPermissionGranted = true; } else { ActivityCompat.requestPermissions( this, new String[] {android.Manifest.permission.ACCESS_FINE_LOCATION}, PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION); } if (!mLocationPermissionGranted) { displayMessage( "Error loading Navigation SDK: " + "The user has not granted location permission."); return; } // Get a navigator. NavigationApi.getNavigator( this, new NavigationApi.NavigatorListener() { /** Sets up the navigation UI when the navigator is ready for use. */ @Override public void onNavigatorReady(Navigator navigator) { displayMessage("Navigator ready."); mNavigator = navigator; mNavFragment = (SupportNavigationFragment) getSupportFragmentManager().findFragmentById(R.id.navigation_fragment); // Get the map. mNavFragment.getMapAsync( new OnMapReadyCallback() { @Override public void onMapReady(GoogleMap map) { mMap = map; // Navigate to a place, specified by Place ID. navigateToPlace(SYDNEY_OPERA_HOUSE); } }); } /** * Handles errors from the Navigation SDK. * * @param errorCode The error code returned by the navigator. */ @Override public void onError(@NavigationApi.ErrorCode int errorCode) { switch (errorCode) { case NavigationApi.ErrorCode.NOT_AUTHORIZED: displayMessage( "Error loading Navigation SDK: Your API key is " + "invalid or not authorized to use the Navigation SDK."); break; case NavigationApi.ErrorCode.TERMS_NOT_ACCEPTED: displayMessage( "Error loading Navigation SDK: User did not accept " + "the Navigation Terms of Use."); break; case NavigationApi.ErrorCode.NETWORK_ERROR: displayMessage("Error loading Navigation SDK: Network error."); break; case NavigationApi.ErrorCode.LOCATION_PERMISSION_MISSING: displayMessage( "Error loading Navigation SDK: Location permission " + "is missing."); break; default: displayMessage("Error loading Navigation SDK: " + errorCode); } } }); } /** Customizes the navigation UI and the map. */ private void customizeNavigationUI() { // Set custom colors for the navigator. mNavFragment.setStylingOptions( new StylingOptions() .primaryDayModeThemeColor(0xff1A237E) .secondaryDayModeThemeColor(0xff3F51B5) .primaryNightModeThemeColor(0xff212121) .secondaryNightModeThemeColor(0xff424242) .headerLargeManeuverIconColor(0xffffff00) .headerSmallManeuverIconColor(0xffffa500) .headerNextStepTypefacePath("/system/fonts/NotoSerif-BoldItalic.ttf") .headerNextStepTextColor(0xff00ff00) .headerNextStepTextSize(20f) .headerDistanceTypefacePath("/system/fonts/NotoSerif-Italic.ttf") .headerDistanceValueTextColor(0xff00ff00) .headerDistanceUnitsTextColor(0xff0000ff) .headerDistanceValueTextSize(20f) .headerDistanceUnitsTextSize(18f) .headerInstructionsTypefacePath("/system/fonts/NotoSerif-BoldItalic.ttf") .headerInstructionsTextColor(0xffffff00) .headerInstructionsFirstRowTextSize(24f) .headerInstructionsSecondRowTextSize(20f) .headerGuidanceRecommendedLaneColor(0xffffa500)); mMap.setTrafficEnabled(false); // Place a marker at the final destination. if (mNavigator.getCurrentRouteSegment() != null) { LatLng destinationLatLng = mNavigator.getCurrentRouteSegment().getDestinationLatLng(); Bitmap destinationMarkerIcon = BitmapFactory.decodeResource(getResources(), R.drawable.ic_person_pin_48dp); mMap.addMarker( new MarkerOptions() .position(destinationLatLng) .icon(BitmapDescriptorFactory.fromBitmap(destinationMarkerIcon)) .title("Destination marker")); // Listen for a tap on the marker. mMap.setOnMarkerClickListener( new GoogleMap.OnMarkerClickListener() { @Override public boolean onMarkerClick(Marker marker) { displayMessage( "Marker tapped: " + marker.getTitle() + ", at location " + marker.getPosition().latitude + ", " + marker.getPosition().longitude); // The event has been handled. return true; } }); } // Set the camera to follow the device location with 'TILTED' driving view. mMap.followMyLocation(CameraPerspective.TILTED); } /** * Requests directions from the user's current location to a specific place (provided by the * Google Places API). */ private void navigateToPlace(String placeId) { Waypoint destination; try { destination = Waypoint.builder().setPlaceIdString(placeId).build(); } catch (Waypoint.UnsupportedPlaceIdException e) { displayMessage("Error starting navigation: Place ID is not supported."); return; } // Create a future to await the result of the asynchronous navigator task. ListenableResultFuture<Navigator.RouteStatus> pendingRoute = mNavigator.setDestination(destination); // Define the action to perform when the SDK has determined the route. pendingRoute.setOnResultListener( new ListenableResultFuture.OnResultListener<Navigator.RouteStatus>() { @Override public void onResult(Navigator.RouteStatus code) { switch (code) { case OK: // Hide the toolbar to maximize the navigation UI. if (getActionBar() != null) { getActionBar().hide(); } // Customize the navigation UI. customizeNavigationUI(); // Enable voice audio guidance (through the device speaker). mNavigator.setAudioGuidance(Navigator.AudioGuidance.VOICE_ALERTS_AND_GUIDANCE); // Simulate vehicle progress along the route for demo/debug builds. if (BuildConfig.DEBUG) { mNavigator .getSimulator() .simulateLocationsAlongExistingRoute( new SimulationOptions().speedMultiplier(5)); } // Start turn-by-turn guidance along the current route. mNavigator.startGuidance(); break; // Handle error conditions returned by the navigator. case NO_ROUTE_FOUND: displayMessage("Error starting navigation: No route found."); break; case NETWORK_ERROR: displayMessage("Error starting navigation: Network error."); break; case ROUTE_CANCELED: displayMessage("Error starting navigation: Route canceled."); break; default: displayMessage("Error starting navigation: " + String.valueOf(code)); } } }); } /** Handles the result of the request for location permissions. */ @Override public void onRequestPermissionsResult( int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { mLocationPermissionGranted = false; switch (requestCode) { case PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION: { // If request is canceled, the result arrays are empty. if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { mLocationPermissionGranted = true; } } } } /** * Shows a message on screen and in the log. Used when something goes wrong. * * @param errorMessage The message to display. */ private void displayMessage(String errorMessage) { Toast.makeText(this, errorMessage, Toast.LENGTH_LONG).show(); Log.d(TAG, errorMessage); } }
ナビゲーション ヘッダーを変更する
SupportNavigationFragment.setStylingOptions()
または NavigationView.setStylingOptions()
を使用して、ナビゲーション ヘッダーのテーマと、ヘッダーの下に表示される次の曲がり角インジケーターを変更します(利用可能な場合)。
次の属性を設定できます。
属性タイプ | 属性 |
---|---|
背景色 |
|
手順のテキスト要素 |
|
次のステップのテキスト要素 |
|
操作アイコン |
|
車線案内 |
|
次の例は、スタイル設定オプションを設定する方法を示しています。
private SupportNavigationFragment mNavFragment;
mNavFragment = (SupportNavigationFragment) getFragmentManager()
.findFragmentById(R.id.navigation_fragment);
// Set the styling options on the fragment.
mNavFragment.setStylingOptions(new StylingOptions()
.primaryDayModeThemeColor(0xff1A237E)
.secondaryDayModeThemeColor(0xff3F51B5)
.primaryNightModeThemeColor(0xff212121)
.secondaryNightModeThemeColor(0xff424242)
.headerLargeManeuverIconColor(0xffffff00)
.headerSmallManeuverIconColor(0xffffa500)
.headerNextStepTypefacePath("/system/fonts/NotoSerif-BoldItalic.ttf")
.headerNextStepTextColor(0xff00ff00)
.headerNextStepTextSize(20f)
.headerDistanceTypefacePath("/system/fonts/NotoSerif-Italic.ttf")
.headerDistanceValueTextColor(0xff00ff00)
.headerDistanceUnitsTextColor(0xff0000ff)
.headerDistanceValueTextSize(20f)
.headerDistanceUnitsTextSize(18f)
.headerInstructionsTypefacePath("/system/fonts/NotoSerif-BoldItalic.ttf")
.headerInstructionsTextColor(0xffffff00)
.headerInstructionsFirstRowTextSize(24f)
.headerInstructionsSecondRowTextSize(20f)
.headerGuidanceRecommendedLaneColor(0xffffa500));
交通状況レイヤをオフにする
GoogleMap.setTrafficEnabled()
を使用して、地図上の交通レイヤを有効または無効にします。この設定は、地図全体に表示される交通量の密度の表示に影響します。ただし、ナビゲーターによってプロットされたルートの交通情報には影響しません。
private GoogleMap mMap;
// Get the map, and when the async call returns, setTrafficEnabled
// (callback will be on the UI thread)
mMap = mNavFragment.getMapAsync(navMap -> navMap.setTrafficEnabled(false));
信号と停止標識を有効にする
ナビゲーションを使用しているときに、地図に信号や一時停止の標識を表示できます。これにより、ルートや運転操作に関する追加のコンテキストが提供されます。
デフォルトでは、Navigation SDK では信号と停止標識は無効になっています。この機能を有効にするには、対象物ごとに DisplayOptions
を個別に呼び出します。
DisplayOptions displayOptions =
new DisplayOptions().showTrafficLights(true).showStopSigns(true);
カスタム マーカーを追加する
Navigation SDK for Android で、マーカーに Google Maps API が使用されるようになりました。詳しくは、Maps API のドキュメントをご覧ください。
フローティング テキスト
フローティング テキストは、Google のアトリビューションを覆わない限り、アプリ内の任意の場所に追加できます。Navigation SDK では、地図上の緯度/経度やラベルにテキストを固定することはできません。詳しくは、情報ウィンドウをご覧ください。
制限速度を表示する
制限速度アイコンはプログラムで表示または非表示にできます。制限速度アイコンの表示と非表示を切り替えるには、NavigationView.setSpeedLimitIconEnabled()
または SupportNavigationFragment.setSpeedLimitIconEnabled()
を使用します。有効にすると、ナビゲーション中に速度制限アイコンが画面の下隅に表示されます。このアイコンは、車が走行している道路の制限速度を示します。このアイコンは、信頼できる制限速度データが利用可能な場所にのみ表示されます。
// Display the Speed Limit icon
mNavFragment.setSpeedLimitIconEnabled(true);
再調整ボタンが表示されると、制限速度アイコンが一時的に非表示になります。
夜間モードを設定する
夜間モードの動作はプログラムで制御できます。NavigationView.setForceNightMode()
または SupportNavigationFragment.setForceNightMode()
を使用して夜間モードをオンまたはオフにするか、Navigation SDK for Android に制御を任せます。
AUTO
Navigation SDK がデバイスの位置情報と現地時間に応じて適切なモードを決定できるようにします。FORCE_NIGHT
は夜間モードを強制的にオンにします。FORCE_DAY
: 日中モードを強制的にオンにします。
次の例は、ナビゲーション フラグメント内で夜間モードを強制的にオンにする方法を示しています。
// Force night mode on.
mNavFragment.setForceNightMode(FORCE_NIGHT);
ルートリストを表示する
まず、ビューを作成して階層に追加します。
void setupDirectionsListView() {
// Create the view.
DirectionsListView directionsListView = new DirectionsListView(getApplicationContext());
// Add the view to your view hierarchy.
ViewGroup group = findViewById(R.id.directions_view);
group.addView(directionsListView);
// Add a button to your layout to close the directions list view.
ImageButton button = findViewById(R.id.close_directions_button); // this button is part of the container we hide in the next line.
button.setOnClickListener(
v -> findViewById(R.id.directions_view_container).setVisibility(View.GONE));
}
NavigationView
の場合と同様に、ライフサイクル イベントを DirectionsListView
に転送してください。次に例を示します。
protected void onResume() {
super.onResume();
directionsListView.onResume();
}
別の経路を非表示にする
ユーザー インターフェースに情報が多すぎて混乱する場合は、デフォルト(2 つ)よりも少ない代替ルートを表示するか、代替ルートをまったく表示しないことで、混乱を軽減できます。このオプションは、ルートを取得する前に、次のいずれかの列挙値を指定して RoutingOptions.alternateRoutesStrategy()
メソッドを呼び出すことで構成できます。
列挙値 | 説明 |
---|---|
AlternateRoutesStrategy.SHOW_ALL | デフォルト。最大 2 つの代替ルートを表示します。 |
AlternateRoutesStrategy.SHOW_ONE | 別のルート(利用可能な場合)を 1 つ表示します。 |
AlternateRoutesStrategy.SHOW_NONE | 別のルートを非表示にします。 |
次のコードサンプルは、代替ルートをすべて非表示にする方法を示しています。
RoutingOptions routingOptions = new RoutingOptions();
routingOptions.alternateRoutesStrategy(AlternateRoutesStrategy.SHOW_NONE);
navigator.setDestinations(destinations, routingOptions, displayOptions);
ルートの進行状況バー
ルートの進行状況バーは、ナビを開始すると地図の右端に縦方向に表示されるバーです。有効にすると、ルート全体の概要と、ユーザーの目的地と現在地が表示されます。
これにより、ユーザーはズームインしなくても、交通などの今後の問題をすばやく予測できます。必要に応じてルートを変更できます。ユーザーがルートを変更すると、その地点から新しいルートとして開始されたかのように、進行状況バーがリセットされます。
ルートの進行状況バーには、次のステータス インジケーターが表示されます。
ルートの経過時間 - ルートの経過時間。
現在の位置 - ルート上のユーザーの現在地。
交通状況 - 今後の交通状況。
最終目的地 - ルートの最終目的地。
NavigationView または SupportNavigationFragment で setTripProgressBarEnabled()
メソッドを呼び出して、ルートの進行状況バーを有効にします。次に例を示します。
// Enable the trip progress bar.
mNavFragment.setTripProgressBarEnabled(true);