Bạn có thể tuỳ chỉnh các thành phần của giao diện người dùng chỉ đường và bản đồ, đồng thời thêm điểm đánh dấu tuỳ chỉnh vào bản đồ. Hãy tham khảo trang Chính sách để biết nguyên tắc về những nội dung sửa đổi được chấp nhận đối với Giao diện người dùng điều hướng.
Xem mã
< > Hiện/ẩn mã Java cho hoạt động điều hướng.
package com.example.navsdkcustomization;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.widget.Toast;
import androidx.annotation.NonNull;
import com.google.android.libraries.navigation.Camera;
import com.google.android.libraries.navigation.LatLng;
import com.google.android.libraries.navigation.ListenableResultFuture;
import com.google.android.libraries.navigation.Marker;
import com.google.android.libraries.navigation.MarkerOptions;
import com.google.android.libraries.navigation.NavigationApi;
import com.google.android.libraries.navigation.NavigationFragment;
import com.google.android.libraries.navigation.NavigationMap;
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.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 NavigationFragment mNavFragment;
private NavigationMap 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 = (NavigationFragment) getFragmentManager()
.findFragmentById(R.id.navigation_fragment);
// 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));
// Get the map.
mMap = mNavFragment.getMap();
// Turn off the traffic layer on the map.
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(destinationMarkerIcon)
.title("Destination marker"));
// Listen for a tap on the marker.
mMap.setOnMarkerClickListener(new NavigationMap.OnMarkerClickListener() {
@Override
public void onMarkerClick(Marker marker) {
displayMessage("Marker tapped: "
+ marker.getTitle() + ", at location "
+ marker.getPosition().latitude + ", "
+ marker.getPosition().longitude);
}
});
}
// Set the camera to follow the device location with 'TILTED' driving view.
mNavFragment.getCamera().followMyLocation(Camera.Perspective.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.fromPlaceId(placeId, null);
} 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);
}
}
Chế độ ban ngày chính – màu ban ngày của tiêu đề điều hướng
Chế độ ban ngày phụ – màu ban ngày của chỉ báo ngã rẽ tiếp theo
Chế độ ban đêm chính – màu ban đêm của tiêu đề điều hướng
Chế độ ban đêm phụ – màu của chỉ báo rẽ tiếp theo
Phần tử văn bản cho hướng dẫn
Màu văn bản
Phông chữ
Kích thước văn bản của hàng đầu tiên
Kích thước văn bản của hàng thứ hai
Phần tử văn bản cho các bước tiếp theo
Phông chữ
Màu văn bản của giá trị khoảng cách
Kích thước văn bản của giá trị khoảng cách
Màu văn bản của đơn vị khoảng cách
Kích thước văn bản của đơn vị khoảng cách
Biểu tượng thao tác
Màu của biểu tượng thao tác lớn
Màu của biểu tượng thao tác nhỏ
Hướng dẫn làn đường
Màu của làn đường được đề xuất
Ví dụ sau đây cho thấy cách đặt các tuỳ chọn định kiểu:
private NavigationFragment mNavFragment;
mNavFragment = (NavigationFragment) 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));
Tắt lớp giao thông
Sử dụng NavigationMap.setTrafficEnabled() để bật hoặc tắt lớp giao thông trên bản đồ. Chế độ cài đặt này ảnh hưởng đến các chỉ báo về mật độ lưu lượng truy cập hiển thị trên toàn bộ bản đồ, nhưng không ảnh hưởng đến các chỉ báo giao thông trên tuyến đường do trình điều hướng vẽ biểu đồ.
private NavigationMap mMap;
// Get the map.
mMap = mNavFragment.getMap();
// Turn off the traffic layer on the map.
mMap.setTrafficEnabled(false);
Thêm điểm đánh dấu tuỳ chỉnh
Bạn có thể thêm điểm đánh dấu tuỳ chỉnh vào bản đồ để cho biết các địa điểm mà ứng dụng hoặc người dùng yêu thích. Ví dụ: bạn có thể muốn cho biết điểm đón ở cuối tuyến đường. Sử dụng NavigationMap.addMarker() để thêm một điểm đánh dấu và NavigationMap.setOnMarkerClickListener() để theo dõi các lượt nhấn vào một điểm đánh dấu.
Đoạn mã dưới đây sử dụng một biểu tượng được lưu trữ trong
tài nguyên có thể vẽ của dự án, R.drawable.ic_person_pin_48dp. Bạn có thể dùng bất kỳ hình ảnh nào phù hợp với ứng dụng của mình.
// 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(destinationMarkerIcon)
.title("Destination marker"));
// Listen for a tap on the marker.
mMap.setOnMarkerClickListener(new NavigationMap.OnMarkerClickListener() {
@Override
public void onMarkerClick(Marker marker) {
displayMessage("Marker tapped: "
+ marker.getTitle() + ", at location "
+ marker.getPosition().latitude + ", "
+ marker.getPosition().longitude);
}
});
}
Bạn có thể chỉ định một hình ảnh tuỳ chỉnh làm điểm đánh dấu; nhưng SDK hiện không hỗ trợ gắn nhãn các hình ảnh này bằng văn bản. Để biết thêm thông tin, hãy xem bài viết Tuỳ chỉnh điểm đánh dấu.
Văn bản nổi
Bạn có thể thêm văn bản nổi ở bất kỳ đâu trong ứng dụng của mình, miễn là thuộc tính của Google chưa được đề cập. SDK Điều hướng không hỗ trợ liên kết văn bản với vĩ độ/kinh độ trên bản đồ hoặc với một nhãn. Để biết thêm thông tin, hãy xem bài viết Cửa sổ thông tin.
AUTO Cho phép SDK điều hướng xác định chế độ phù hợp theo vị trí của thiết bị và giờ địa phương.
FORCE_NIGHT buộc bật chế độ ban đêm.
FORCE_DAY buộc bật chế độ ban ngày.
Ví dụ sau đây cho thấy việc buộc bật chế độ ban đêm trong một mảnh điều hướng:
// Force night mode on.
mNavFragment.setForceNightMode(FORCE_NIGHT);
Hiển thị danh sách đường đi
Trước tiên, hãy tạo chế độ xem rồi thêm chế độ xem đó vào hệ phân cấp của bạn.
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));
}
Hãy nhớ chuyển tiếp các sự kiện trong vòng đời đến GuidelinesListView giống như với NaviagtionView. Ví dụ:
Khi giao diện người dùng trở nên lộn xộn với quá nhiều thông tin, bạn có thể giảm sự lộn xộn bằng cách cho thấy ít tuyến thay thế hơn so với mặc định (hai) hoặc bằng cách không hiển thị tuyến đường thay thế nào. Bạn có thể định cấu hình tuỳ chọn này trước khi tìm nạp các tuyến bằng cách gọi phương thức RoutingOptions.alternateRoutesStrategy() với một trong các giá trị liệt kê sau:
Giá trị liệt kê
Nội dung mô tả
AlternateRoutesStrategy.SHOW_ALL
Mặc định. Hiển thị tối đa hai tuyến thay thế.
AlternateRoutesStrategy.SHOW_ONE
Hiển thị một tuyến thay thế (nếu có).
AlternateRoutesStrategy.SHOW_NONE
Ẩn các tuyến đường thay thế.
Ví dụ:
Ví dụ về mã sau đây minh hoạ cách ẩn hoàn toàn các tuyến thay thế.
RoutingOptions routingOptions = new RoutingOptions();
routingOptions.alternateRoutesStrategy(AlternateRoutesStrategy.SHOW_NONE);
navigator.setDestinations(destinations, routingOptions, displayOptions);