Customize Navigation View UI elements

Navigation View is the UI provided to show the navigation route process. In this example we will show how to do customization on Navigation View, including:

  • Add a new UI element by customizing the activity layout

  • Show or hide existing Navigation View UI elements

As is shown in the above image, we customized the Navigation View app bar and added a switch button to it. A user tapping the switch button will change the visibility of two UI elements (Recenter Button and Sound button), which are originally existing in Navigation View.

For all code examples, refer to Navigation Code Examples

docs-image

activity_custom_element_visibility.xml view source

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".activity.CustomElementVisibilityActivity">

    <ai.nextbillion.navigation.ui.NavigationView
        android:id="@+id/custom_element_navigation_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</androidx.constraintlayout.widget.ConstraintLayout>

CustomElementVisibilityActivity view source

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
package ai.nextbillion.navigation.demo.activity;

import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;

import ai.nextbillion.kits.directions.models.DirectionsResponse;
import ai.nextbillion.kits.directions.models.RouteRequestParams;
import ai.nextbillion.navigation.core.routefetcher.RequestParamsWrapper;
import ai.nextbillion.navigation.demo.R;
import ai.nextbillion.navigation.ui.NavViewConfig;
import ai.nextbillion.navigation.ui.NavigationView;
import ai.nextbillion.navigation.ui.OnNavigationReadyCallback;
import ai.nextbillion.navigation.ui.listeners.NavigationListener;

import android.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.SwitchCompat;


import java.io.IOException;
import java.io.InputStream;
import java.util.Scanner;

/***
 * This class demonstrates how to add an extra switch button on Appbar
 * and use the switch button to control the display of UI elements in Navigation view
 */

public class CustomElementVisibilityActivity extends AppCompatActivity implements OnNavigationReadyCallback, NavigationListener {
    private NavigationView navigationView;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_custom_element_visibility);
        navigationView = findViewById(R.id.custom_element_navigation_view);
        navigationView.onCreate(savedInstanceState);
        navigationView.initialize(this);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.mainmenu, menu);
        MenuItem item = menu.findItem(R.id.myswitch);
        SwitchCompat mySwitch = (SwitchCompat) item.getActionView();

        // adding this here to keep the initial display consistency of the UI elements
        controlDisplayOfElements(mySwitch.isChecked());
        // The on-click event will be triggered each time user clicks the switch button on the App bar
        mySwitch.setOnCheckedChangeListener((buttonView, isChecked) -> {
            controlDisplayOfElements(isChecked);
        });
        return true;
    }

    private void controlDisplayOfElements(boolean shouldDisplay) {
        if (shouldDisplay) {
            navigationView.showRecenterBtn();
            navigationView.retrieveSoundButton().show();
        } else {
            navigationView.hideRecenterBtn();
            navigationView.retrieveSoundButton().hide();
        }
    }

    @Override
    public void onNavigationReady(boolean b) {
        // read original backend response from file
        DirectionsResponse response = DirectionsResponse.fromJson(loadJsonFromAsset());
        // modify the backend response following normal api call process
        DirectionsResponse modifiedResponse = new RequestParamsWrapper().wrapRequestParams(response, RouteRequestParams.builder().build());
        NavViewConfig.Builder config =
                NavViewConfig.builder().route(modifiedResponse.routes().get(0))
                        // The visibility of speedometer can be set here before starting navigation
                        .showSpeedometer(true)
                        // add this so the exit button in Navigation view would work
                        .navigationListener(this)
                        .shouldSimulateRoute(true);
        navigationView.startNavigation(config.build());
    }

    private static String convertStreamToString(InputStream is) {
        Scanner s = new Scanner(is).useDelimiter("\\A");
        return s.hasNext() ? s.next() : "";
    }

    private String loadJsonFromAsset() {
        // Using this method to load GeoJSON files from the assets folder.
        try {
            return convertStreamToString(getApplicationContext().getAssets().open("directions-route.json"));
        } catch (IOException ex) {
            ex.printStackTrace();
            return null;
        }
    }

    @Override
    public void onStart() {
        super.onStart();
        navigationView.onStart();
    }

    @Override
    public void onResume() {
        super.onResume();
        navigationView.onResume();
    }

    @Override
    public void onLowMemory() {
        super.onLowMemory();
        navigationView.onLowMemory();
    }

    @Override
    public void onBackPressed() {
        // If the navigation view didn't need to do anything, call super
        if (!navigationView.onBackPressed()) {
            super.onBackPressed();
        }
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        navigationView.onSaveInstanceState(outState);
        super.onSaveInstanceState(outState);
    }

    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        navigationView.onRestoreInstanceState(savedInstanceState);
    }


    @Override
    public void onPause() {
        super.onPause();
        navigationView.onPause();
    }

    @Override
    public void onStop() {
        super.onStop();
        navigationView.onStop();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        navigationView.onDestroy();
    }

    @Override
    public void onCancelNavigation() {
        finish();
    }

    @Override
    public void onNavigationFinished() {

    }

    @Override
    public void onNavigationRunning() {

    }
}

Code Highlights

The main logic of the code example is to use a switch button to control the visibility of the Recenter button and the Sound button in the navigation view.

The controlDisPlayOfElement() function shows how to display or hide the corresponding view during navigation.

Code summary

The code snippet is for an Android activity that allows users to control the visibility of elements in a navigation view. The activity extends the AppCompatActivity class and implements the OnNavigationReadyCallback and NavigationListener interfaces.

The activity's onCreate() method first inflates the activity_custom_element_visibility layout. It then finds the navigationView view in the layout and calls its onCreate() method. Finally, it calls the initialize() method on the navigationView to initialize it.

The activity's onCreateOptionsMenu() method inflates the mainmenu menu. It then finds the myswitch menu item and gets its SwitchCompat view. The activity then calls the controlDisplayOfElements() method to set the initial visibility of the elements in the navigation view. The activity also sets a listener on the myswitch view so that it can be updated when the user changes the switch's state.

The controlDisplayOfElements() method takes a boolean value as input. If the value is true, the method shows the Recenter button and the Sound button in the navigation view. If the value is false, the method hides the buttons.

The onNavigationReady() method is called when the navigation view is ready. The method reads the original backend response from a file. It then modifies the response and creates a NavViewConfig object. The NavViewConfig object specifies the route that will be navigated, whether the speedometer will be shown and whether the navigation listener will be used. The method then calls the startNavigation() method on the navigation view to start navigation.

The convertStreamToString() method converts an input stream to a string. The method uses a Scanner object to read the stream and a delimiter to determine where the stream ends.

The loadJsonFromAsset() method loads a GeoJSON file from the assets folder. The method tries to open the file and read its contents. If the file cannot be opened, the method returns null.

The activity uses the NavigationView class to display a navigation view in the user interface. The activity also uses the OnNavigationReadyCallback and NavigationListener interfaces to interact with the navigation view.

Have Questions ?