這個自訂控制項位置專為自訂頁尾檢視畫面而設計。如果您看到 Nav SDK ETA 資訊卡,這個控制項會顯示在資訊卡上方。如果沒有,控制項會與地圖底部對齊。與 BOTTOM_START_BELOW 和 BOTTOM_END_BELOW 自訂控制項不同,這個控制項會置於可見地圖邊界之外,也就是說,新增至地圖的任何邊框都不會變更這個控制項的位置。
在 portrait mode 中,自訂頁尾會以全寬顯示。CustomControlPosition.BOTTOM_START_BELOW 和 CustomControlPosition.BOTTOM_END_BELOW 位置的自訂控制項,以及重新置準心按鈕和 Google 標誌等 Nav SDK UI 元素,會位於自訂控制項頁尾上方。箭頭的預設位置會考量自訂頁尾高度。
在 landscape mode 中,自訂頁尾的寬度為一半,並與起始邊 (LTR 中的左側) 對齊,就像 Nav SDK ETA 資訊卡一樣。CustomControlPosition.BOTTOM_START_BELOW 位置中的自訂控制項,以及重新置中按鈕和 Google 標誌等 Nav SDK UI 元素,會位於自訂控制項頁尾的上方。CustomControlPosition.BOTTOM_END_BELOW 位置的自訂控制項,以及沿著端側 (LTR 為右側) 的任何 Nav SDK UI 元素,都會與地圖底部對齊。自訂頁尾不會延伸至地圖的結尾,因此在自訂頁尾出現時,箭頭的預設位置不會改變。
CustomControlPosition.BOTTOM_START_BELOW 和 CustomControlPosition.BOTTOM_END_BELOW 位置的自訂控制項,以及重新置中心按鈕和 Google 標誌等 Nav SDK UI 元素,會位於自訂控制項頁尾的上方。
地圖 UI 配件
Navigation SDK for Android 提供 UI 配件,可在導航期間顯示類似於 Google 地圖 Android 應用程式中的配件。您可以按照本節所述調整這些控制項的顯示設定或外觀。您在這裡所做的變更會在下一個導覽工作階段中反映。
packagecom.example.navsdkcustomization;importandroid.content.pm.PackageManager;importandroid.graphics.Bitmap;importandroid.graphics.BitmapFactory;importandroid.os.Bundle;importandroid.util.Log;importandroid.widget.Toast;importandroidx.annotation.NonNull;importandroidx.appcompat.app.AppCompatActivity;importandroidx.core.app.ActivityCompat;importandroidx.core.content.ContextCompat;importcom.google.android.gms.maps.GoogleMap;importcom.google.android.gms.maps.GoogleMap.CameraPerspective;importcom.google.android.gms.maps.OnMapReadyCallback;importcom.google.android.gms.maps.model.BitmapDescriptorFactory;importcom.google.android.gms.maps.model.LatLng;importcom.google.android.gms.maps.model.Marker;importcom.google.android.gms.maps.model.MarkerOptions;importcom.google.android.libraries.navigation.ListenableResultFuture;importcom.google.android.libraries.navigation.NavigationApi;importcom.google.android.libraries.navigation.Navigator;importcom.google.android.libraries.navigation.SimulationOptions;importcom.google.android.libraries.navigation.StylingOptions;importcom.google.android.libraries.navigation.SupportNavigationFragment;importcom.google.android.libraries.navigation.Waypoint;/**AnactivitythatdisplaysamapandacustomizednavigationUI.*/publicclassNavigationActivityCustomizationextendsAppCompatActivity{privatestaticfinalStringTAG=NavigationActivityCustomization.class.getSimpleName();privateNavigatormNavigator;privateSupportNavigationFragmentmNavFragment;privateGoogleMapmMap;//DefinetheSydneyOperaHousebyspecifyingitsplaceID.privatestaticfinalStringSYDNEY_OPERA_HOUSE="ChIJ3S-JXmauEmsRUcIaWtf4MzE";//Setfieldsforrequestinglocationpermission.privatestaticfinalintPERMISSIONS_REQUEST_ACCESS_FINE_LOCATION=1;privatebooleanmLocationPermissionGranted;@OverrideprotectedvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);//InitializetheNavigationSDK.initializeNavigationSdk();}/***StartstheNavigationSDKandsetsthecameratofollowthedevice's location. Calls the*navigateToPlace()methodwhenthenavigatorisready.*/privatevoidinitializeNavigationSdk(){/**Requestlocationpermission,sothatwecangetthelocationofthe*device.Theresultofthepermissionrequestishandledbyacallback,*onRequestPermissionsResult.*/if(ContextCompat.checkSelfPermission(this.getApplicationContext(),android.Manifest.permission.ACCESS_FINE_LOCATION)==PackageManager.PERMISSION_GRANTED){mLocationPermissionGranted=true;}else{ActivityCompat.requestPermissions(this,newString[]{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;}//Getanavigator.NavigationApi.getNavigator(this,newNavigationApi.NavigatorListener(){/**SetsupthenavigationUIwhenthenavigatorisreadyforuse.*/@OverridepublicvoidonNavigatorReady(Navigatornavigator){displayMessage("Navigator ready.");mNavigator=navigator;mNavFragment=(SupportNavigationFragment)getSupportFragmentManager().findFragmentById(R.id.navigation_fragment);//Getthemap.mNavFragment.getMapAsync(newOnMapReadyCallback(){@OverridepublicvoidonMapReady(GoogleMapmap){mMap=map;//Navigatetoaplace,specifiedbyPlaceID.navigateToPlace(SYDNEY_OPERA_HOUSE);}});}/***HandleserrorsfromtheNavigationSDK.**@paramerrorCodeTheerrorcodereturnedbythenavigator.*/@OverridepublicvoidonError(@NavigationApi.ErrorCodeinterrorCode){switch(errorCode){caseNavigationApi.ErrorCode.NOT_AUTHORIZED:displayMessage("Error loading Navigation SDK: Your API key is "+"invalid or not authorized to use the Navigation SDK.");break;caseNavigationApi.ErrorCode.TERMS_NOT_ACCEPTED:displayMessage("Error loading Navigation SDK: User did not accept "+"the Navigation Terms of Use.");break;caseNavigationApi.ErrorCode.NETWORK_ERROR:displayMessage("Error loading Navigation SDK: Network error.");break;caseNavigationApi.ErrorCode.LOCATION_PERMISSION_MISSING:displayMessage("Error loading Navigation SDK: Location permission "+"is missing.");break;default:displayMessage("Error loading Navigation SDK: "+errorCode);}}});}/**CustomizesthenavigationUIandthemap.*/privatevoidcustomizeNavigationUI(){//Setcustomcolorsforthenavigator.mNavFragment.setStylingOptions(newStylingOptions().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);//Placeamarkeratthefinaldestination.if(mNavigator.getCurrentRouteSegment()!=null){LatLngdestinationLatLng=mNavigator.getCurrentRouteSegment().getDestinationLatLng();BitmapdestinationMarkerIcon=BitmapFactory.decodeResource(getResources(),R.drawable.ic_person_pin_48dp);mMap.addMarker(newMarkerOptions().position(destinationLatLng).icon(BitmapDescriptorFactory.fromBitmap(destinationMarkerIcon)).title("Destination marker"));//Listenforataponthemarker.mMap.setOnMarkerClickListener(newGoogleMap.OnMarkerClickListener(){@OverridepublicbooleanonMarkerClick(Markermarker){displayMessage("Marker tapped: "+marker.getTitle()+", at location "+marker.getPosition().latitude+", "+marker.getPosition().longitude);//Theeventhasbeenhandled.returntrue;}});}//Setthecameratofollowthedevicelocationwith'TILTED'drivingview.mMap.followMyLocation(CameraPerspective.TILTED);}/***Requestsdirectionsfromtheuser's current location to a specific place (provided by the*GooglePlacesAPI).*/privatevoidnavigateToPlace(StringplaceId){Waypointdestination;try{destination=Waypoint.builder().setPlaceIdString(placeId).build();}catch(Waypoint.UnsupportedPlaceIdExceptione){displayMessage("Error starting navigation: Place ID is not supported.");return;}//Createafuturetoawaittheresultoftheasynchronousnavigatortask.ListenableResultFuture<Navigator.RouteStatus> pendingRoute=mNavigator.setDestination(destination);//DefinetheactiontoperformwhentheSDKhasdeterminedtheroute.pendingRoute.setOnResultListener(newListenableResultFuture.OnResultListener<Navigator.RouteStatus>(){@OverridepublicvoidonResult(Navigator.RouteStatuscode){switch(code){caseOK://HidethetoolbartomaximizethenavigationUI.if(getActionBar()!=null){getActionBar().hide();}//CustomizethenavigationUI.customizeNavigationUI();//Enablevoiceaudioguidance(throughthedevicespeaker).mNavigator.setAudioGuidance(Navigator.AudioGuidance.VOICE_ALERTS_AND_GUIDANCE);//Simulatevehicleprogressalongtheroutefordemo/debugbuilds.if(BuildConfig.DEBUG){mNavigator.getSimulator().simulateLocationsAlongExistingRoute(newSimulationOptions().speedMultiplier(5));}//Startturn-by-turnguidancealongthecurrentroute.mNavigator.startGuidance();break;//Handleerrorconditionsreturnedbythenavigator.caseNO_ROUTE_FOUND:displayMessage("Error starting navigation: No route found.");break;caseNETWORK_ERROR:displayMessage("Error starting navigation: Network error.");break;caseROUTE_CANCELED:displayMessage("Error starting navigation: Route canceled.");break;default:displayMessage("Error starting navigation: "+String.valueOf(code));}}});}/**Handlestheresultoftherequestforlocationpermissions.*/@OverridepublicvoidonRequestPermissionsResult(intrequestCode,@NonNullString[]permissions,@NonNullint[]grantResults){mLocationPermissionGranted=false;switch(requestCode){casePERMISSIONS_REQUEST_ACCESS_FINE_LOCATION:{//Ifrequestiscanceled,theresultarraysareempty.if(grantResults.length > 0 && grantResults[0]==PackageManager.PERMISSION_GRANTED){mLocationPermissionGranted=true;}}}}/***Showsamessageonscreenandinthelog.Usedwhensomethinggoeswrong.**@paramerrorMessageThemessagetodisplay.*/privatevoiddisplayMessage(StringerrorMessage){Toast.makeText(this,errorMessage,Toast.LENGTH_LONG).show();Log.d(TAG,errorMessage);}}
privateSupportNavigationFragmentmNavFragment;mNavFragment=(SupportNavigationFragment)getFragmentManager().findFragmentById(R.id.navigation_fragment);// Set the styling options on the fragment.mNavFragment.setStylingOptions(newStylingOptions().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));
privateGoogleMapmMap;// Get the map, and when the async call returns, setTrafficEnabled// (callback will be on the UI thread)mMap=mNavFragment.getMapAsync(navMap->navMap.setTrafficEnabled(false));
// Force night mode on.mNavFragment.setForceNightMode(FORCE_NIGHT);
顯示路線清單
首先,請建立檢視畫面並將其新增至階層。
voidsetupDirectionsListView(){// Create the view.DirectionsListViewdirectionsListView=newDirectionsListView(getApplicationContext());// Add the view to your view hierarchy.ViewGroupgroup=findViewById(R.id.directions_view);group.addView(directionsListView);// Add a button to your layout to close the directions list view.ImageButtonbutton=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));}
[null,null,["上次更新時間:2024-12-22 (世界標準時間)。"],[[["The Android Navigation SDK offers UI customization through predefined map UI controls and accessories, allowing developers to tailor the navigation experience."],["Developers can style elements like the navigation header, traffic layer, and speed limit display, as well as manage night mode and route display options."],["Custom markers and floating text can be added using Google Maps APIs, with adherence to attribution guidelines."],["`SupportNavigationFragment` is recommended for better integration and handling of the NavigationView."],["Always call UI customization methods on the UI thread to avoid rendering issues."]]],[]]