> For the complete documentation index, see [llms.txt](https://docs.mapbox.com/android/navigation/v2/llms.txt)

# Customize Drop-In UI

Even though Drop-In UI comes with preset UI components arranged in a layout, you can customize it in three different ways:

-   **ViewStyleCustomization**: Style the default UI components supported by Drop-In UI.
-   **ViewBinderCustomization**: Swap the default UI components with your custom designed views.
-   **ViewOptionsCustomization**: Change the default values for the attributes otherwise specified by Drop-In UI.

## Style UI Components

`ViewStyleCustomization` can be used to change the style of an existing UI component at runtime. This includes:

-   **infoPanelPeekHeight**: Change the peek height value of the info panel.
-   **infoPanelMarginStart**: Change the start margin value of the info panel.
-   **infoPanelMarginEnd**: Change the end margin value of the info panel.
-   **infoPanelBackground**: Change the background of the info panel.
-   **poiNameTextAppearance**: Update the text appearance of the view showing POI details.
-   **destinationMarkerAnnotationOptions**: Update the `PointAnnotationOptions` used to draw destination marker.
-   **roadNameBackground**: Change the background of the `RoadNameView`.
-   **roadNameTextAppearance**: Update the text appearance of the `RoadNameView`.
-   **tripProgressStyle**: Update the style of `MapboxTripProgressView`.
-   **speedLimitStyle**: Update the style of `MapboxSpeedLimitView`.
-   **speedLimitTextAppearance**: Update the text appearance of `MapboxSpeedLimitView`.
-   **recenterButtonStyle**: Update the style of `MapboxExtendableButton`, representing the recenter button.
-   **cameraModeButtonStyle**: Update the style of `MapboxCameraModeButton`.
-   **compassButtonStyle**: Update the style of `MapboxExtendableButton`, representing the compass button.
-   **audioGuidanceButtonStyle**: Update the style of `MapboxAudioGuidanceButton`.
-   **routePreviewButtonStyle**: Update the style of `MapboxExtendableButton`, representing the route preview button.
-   **endNavigationButtonStyle**: Update the style of `MapboxExtendableButton`, representing the end navigation button.
-   **startNavigationButtonStyle**: Update the style of `MapboxExtendableButton`, representing the start navigation button.
-   **maneuverViewOptions**: Update the style of `MapboxManeuverView`.
-   **arrivalTextAppearance**: Update the text appearance of the view showing arrival details.
-   **locationPuckOptions**: Update the location puck.

Use the following code snippet to apply runtime styling changes to `MapboxRoadNameView`.

Add your custom style to `styles.xml` or `themes.xml`:

```XML
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <style name="MyCustomRoadNameViewTextAppearance" parent="TextAppearance.AppCompat">
      <item name="android:textColor">#333333</item>
      <item name="android:textSize">16sp</item>
      <item name="android:textStyle">bold</item>
    </style>
</resources>
```

Create your custom background drawable:

```XML
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
    <corners android:radius="30dp" />
    <solid android:color="#FFFFFF" />
    <stroke android:color="#EDEDED" android:width="1dp" />
</shape>
```

In your `Activity` or `Fragment`, invoke the function to change the appearance any time:

```kotlin
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.your_layout)
    findViewById<NavigationView>(R.id.navigationView).customizeViewStyles {
        roadNameBackground = R.drawable.my_custom_drawable
        roadNameTextAppearance = R.style.MyCustomRoadNameViewTextAppearance
    }
}
```

| Default road name view | Custom road name view |
| --- | --- |
| ![A Navigation UI displaying the default road name view text appearance and background.](https://docs.mapbox.com/android/assets/ideal-img/navigation-drop-in-ui-default-road-name-view.fe8b9d7.480.jpg) | ![A Navigation UI displaying the custom road name view text appearance and background.](https://docs.mapbox.com/android/assets/ideal-img/navigation-drop-in-ui-custom-road-name-view.5a07849.480.jpg) |

Similarly, you can customize the other standalone UI components listed above and apply it to the `NavigationView` at runtime.

> **Related content (example): [Custom runtime styling with NavigationView](https://docs.mapbox.com/android/navigation/v2/examples/navigation-view-custom-runtime-styling/)**
> 
> Render custom runtime styling of default UI components to be used with the `NavigationView`

## Customize options

`NavigationView` exposes options that can be used to define the behavior of the components associated with it. This includes:

-   **mapStyleUriDay**: Apply custom day styles to `MapView`.
-   **mapStyleUriNight**: Apply custom night styles to `MapView`.
-   **routeLineOptions**: Apply custom `MapboxRouteLineOptions`.
-   **routeArrowOptions**: Apply custom `RouteArrowOptions`.
-   **showInfoPanelInFreeDrive**: Toggle the property to show/hide info panel in free drive state.
-   **enableMapLongClickIntercept**: Toggle the property to handle long press events on `MapView`.
-   **isInfoPanelHideable**: Toggle the property to allow the info panel to hide completely when swiped down.
-   **infoPanelForcedState**: Apply `BottomSheet.State` to the info panel.
-   **distanceFormatterOptions**: Apply `DistanceFormatterOptions` that would be used by `MapboxManeuverView`.
-   **showCameraDebugInfo**: Toggle the property to visualize navigation camera debug window.
-   **showManeuver**: Toggle the property to show/hide `MapboxManeuverView`.
-   **showSpeedLimit**: Toggle the property to show/hide `MapboxSpeedLimitView`.
-   **showRoadName**: Toggle the property to show/hide `MapboxRoadNameView`.
-   **showTripProgress**: Toggle the property to show/hide `MapboxTripProgressView`.
-   **showActionButtons**: Toggle the property to show/hide all action buttons.
-   **showCompassActionButton**: Toggle the property to show/hide compass action button.
-   **showCameraModeActionButton**: Toggle the property to show/hide `MapboxCameraModeButton`.
-   **showToggleAudioActionButton**: Toggle the property to show/hide `MapboxAudioGuidanceButton`.
-   **showRecenterActionButton**: Toggle the property to show/hide the recenter action button.
-   **showRoutePreviewButton**: Toggle the property to show/hide the route preview button.
-   **showEndNavigationButton**: Toggle the property to show/hide the end navigation button.
-   **showStartNavigationButton**: Toggle the property to show/hide the start navigation button.

To change the appearance of the route line, define `MapboxRouteLineOptions` and apply it to `NavigationView`.

```kotlin
class MyActivity: AppCompatActivity() {
    private val routeLineOption: MapboxRouteLineOptions by lazy {
        MapboxRouteLineOptions.Builder(this)
            .withRouteLineResources(
                RouteLineResources.Builder()
                    .routeLineColorResources(
                        RouteLineColorResources.Builder()
                            .routeLowCongestionColor(Color.YELLOW)
                            .routeCasingColor(Color.RED)
                            .build()
                    )
                    .build()
            )
            .withRouteLineBelowLayerId("road-label") // for Style.LIGHT and Style.DARK
            .withVanishingRouteLineEnabled(true)
            .displaySoftGradientForTraffic(true)
            .build()
    }
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.your_activity_layout)
        findViewById<NavigationView>(R.id.navigationView).customizeViewOptions {
            mapStyleUriDay = Style.LIGHT
            routeLineOptions = this@MyActivity.routeLineOption
        }
    }
}
```

| Default route line options | Custom route line options |
| --- | --- |
| ![A Navigation UI displaying the default route line view.](https://docs.mapbox.com/android/assets/ideal-img/navigation-drop-in-ui-default-route-line.08e7ca5.480.jpg) | ![A Navigation UI displaying the custom route line view.](https://docs.mapbox.com/android/assets/ideal-img/navigation-drop-in-ui-custom-route-line.16df709.480.jpg) |

Similarly, you can change the other options listed above and apply it to `NavigationView` at runtime.

> **Related content (example): [Define options used by NavigationView](https://docs.mapbox.com/android/navigation/v2/examples/navigation-view-options/)**
> 
> Apply `ViewOptionsCustomization` at runtime.

## Swap UI Components with custom views

`ViewBinderCustomization` can be used to replace the UI components created by Drop-In UI with your own custom design. This includes:

-   **maneuverBinder**: Swap default `MapboxManeuverView` with your custom maneuver view.
-   **roadNameBinder**: Swap default `MapboxRoadNameView` with your custom road name view.
-   **speedLimitBinder**: Swap default `MapboxSpeedLimitView` with your custom speed limit view.
-   **actionButtonsBinder**: Swap all action buttons with your custom action buttons.
-   **actionCompassButtonBinder**: Swap the compass action button with your custom compass button.
-   **actionRecenterButtonBinder**: Swap the recenter action button with your custom recenter button.
-   **actionCameraModeButtonBinder**: Swap `MapboxCameraModeButton` with your custom camera mode button.
-   **actionToggleAudioButtonBinder**: Swap `MapboxAudioGuidanceButton` with your custom audio guidance button.
-   **leftFrameBinder**: Use the left frame to inject additional content below speed limit UI.
-   **rightFrameBinder**: Use the right frame to inject additional content below action buttons.
-   **customActionButtons**: Use the property to inject additional action buttons either at the start or end of existing action buttons.
-   **mapViewBinder**: Swap the default `MapView` instance with your custom `MapView`.
-   **infoPanelBinder**: Use the property to swap the default info panel with custom design.
-   **infoPanelTripProgressBinder**: Use the property to swap `MapboxTripProgressView` with your custom design.
-   **infoPanelHeaderBinder**: Use the property to define custom header view for the info panel. The custom view supplied here will be used.
-   **infoPanelHeaderFreeDriveBinder**: Use the property to define custom header view for the info panel specific to free drive state when using the default infoPanelHeaderBinder.
-   **infoPanelHeaderDestinationPreviewBinder**: Use the property to define custom header view for the info panel specific to destination preview state when using the default infoPanelHeaderBinder.
-   **infoPanelHeaderRoutePreviewBinder**: Use the property to define custom header view for the info panel specific to route preview state when using the default infoPanelHeaderBinder.
-   **infoPanelHeaderActiveGuidanceBinder**: Use the property to define custom header view for the info panel specific to active guidance state when using the default infoPanelHeaderBinder.
-   **infoPanelHeaderArrivalBinder**: Use the property to define custom header view for the info panel specific to arrival state when using the default infoPanelHeaderBinder.
-   **infoPanelContentBinder**: Use the property to define custom content view for the info panel.
-   **infoPanelRoutePreviewButtonBinder**: Swap the route preview button with your custom design.
-   **infoPanelEndNavigationButtonBinder**: Swap the end navigation button with your custom design.
-   **infoPanelStartNavigationButtonBinder**: Swap the start navigation button with your custom design.

Use the following code snippets to swap the default UI component with a custom designed view:

### Define the layout for custom view

```XML
<?xml version="1.0" encoding="utf-8"?>
<merge 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="wrap_content"
    android:layout_height="wrap_content"
    tools:parentTag="android.widget.FrameLayout">

<TextView
        android:id="@+id/speedLimit"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:textSize="18sp"
        android:textColor="@android:color/black"
        android:gravity="center"
        android:background="@android:color/white"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintEnd_toStartOf="parent"/>
</merge>
```

> **Note: Merge into a FrameLayout**
> 
> Drop-In UI uses `FrameLayout` as a container to display views on top of the `MapView`. All UI Components and custom views are merged into the parent `FrameLayout`, each of which has a specific bound set on the screen. For a better understanding of the bounds, refer to [`mapbox_navigation_view_layout`](https://github.com/zicyApp/mapbox-navigation-android/blob/27a84acfc138bd6be87355b5669a51af24986769/libnavui-dropin/src/main/res/layout/mapbox_navigation_view_layout.xml).

### Create a `UIComponent`

`UIComponent` is an interface that gives you access to `MapboxNavigation` and `coroutineScope`. When the `UIComponent` is attached and detached from the binder, it invokes `onAttached` and `onDetached` respectively. All coroutines that you launch in `onAttached` are canceled automatically when the observer is detached which means you don't have to explicitly override `onDetached` in your custom `UIComponent`. This is where you add your business logic and wire the data to the custom view. For example, you can register to [`RouteProgressObserver`](https://docs.mapbox.com/android/navigation/v2/api/2.22.2/libnavigation-core/com.mapbox.navigation.core.trip.session/-route-progress-observer/) using `mapboxNavigation` and extract the necessary data points from it.

```kotlin
class MySpeedLimitComponent(
    private val speedLimit: MySpeedLimitLayoutBinding
) : UIComponent() {

    override fun onAttached(mapboxNavigation: MapboxNavigation) {
        super.onAttached(mapboxNavigation)
        mapboxNavigation.flowLocationMatcherResult().collect {
            val postedSpeedLimit = it.speedLimit?.speedKmph

            textView.text = when {
                postedSpeedLimit != null -> "Speed Limit\n $postedSpeedLimit"
                else -> "--"
            }
        }
    }
}
```

### Create a `UIBinder`

`UIBinder` is an interface responsible for transitioning view(s) into [`ViewGroup`](https://developer.android.com/reference/android/view/ViewGroup).

```kotlin
@OptIn(ExperimentalPreviewMapboxNavigationAPI::class)
private class MySpeedLimitViewBinder : UIBinder {
    override fun bind(viewGroup: ViewGroup): MapboxNavigationObserver {
        val scene = Scene.getSceneForLayout(
            viewGroup,
            R.layout.my_speed_limit_layout,
            viewGroup.context
        )
        TransitionManager.go(scene, Fade())

        val binding = MySpeedLimitLayoutBinding.bind(viewGroup)
        return MySpeedLimitComponent(binding)
    }
}
```

The function `bind` defines the transition of speed limit view into the `viewGroup` using a [`Fade`](https://developer.android.com/reference/android/transition/Fade) transition. You can choose to inflate your custom layout or opt in for a different [`transition`](https://developer.android.com/develop/ui/views/animations/transitions) based on app requirements.

Finally, apply your custom view binder to `NavigationView`

```kotlin
class MyActivity: AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.your_activity_layout)
        findViewById<NavigationView>(R.id.navigationView).customizeViewBinders {
            speedLimitBinder = MySpeedLimitViewBinder()
        }
    }
}
```

| Default speed limit | Custom speed limit |
| --- | --- |
| ![A Navigation UI displaying the default speed limit view.](https://docs.mapbox.com/android/assets/ideal-img/navigation-drop-in-ui-default-speed-limit.64b65ca.480.jpg) | ![A Navigation UI displaying a custom designed speed limit view.](https://docs.mapbox.com/android/assets/ideal-img/navigation-drop-in-ui-custom-speed-limit.37700d0.480.jpg) |

Similarly, you can replace the other UI components listed above with your custom designs and apply it to the `NavigationView` at runtime.

> **Related content (example): [Custom speed limit with NavigationView](https://docs.mapbox.com/android/navigation/v2/examples/navigation-view-custom-speed-limit/)**
> 
> Render custom speed limit view to be used with the `NavigationView`

## View Injection

There can be use cases where you want to use the Drop-In UI in a mostly default state, but also use a few additional capabilities. For example, if you are a logistics company, you might want to add delivery instructions for your driver, or if you are an automotive company, you might want to add controls that enable drivers to zoom in and out. Drop-In UI exposes these capabilities using:

-   `ViewBinderCustomization.infoPanelContentBinder`
-   `ViewBinderCustomization.leftFrameBinder`
-   `ViewBinderCustomization.rightFrameBinder`

These are additional empty frames where Drop-In UI doesn't add any content by default, but enables you to add any custom view to the hierarchy.

Use the following code snippets to inject a custom view:

### Define the layout for custom view

```xml
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    tools:parentTag="android.widget.FrameLayout">

<TextView
        android:id="@+id/content"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:padding="8dp"
        android:textSize="18sp"
        android:textColor="#616161"
        android:visibility="gone"
        tools:visibility="visible"
        android:text="Leave the parcel at my doorstep"
        />
</merge>
```

### Create a `UIComponent`

The content is only visible once the user enters the `ActiveNavigation` state.

```kotlin
class MyInfoPanelContentComponent(private val content: TextView) : UIComponent() {

    override fun onAttached(mapboxNavigation: MapboxNavigation) {
        super.onAttached(mapboxNavigation)
        mapboxNavigation.flowRoutesUpdated().observe {
            content.isVisible = it.navigationRoutes.isNotEmpty()
        }
    }
}
```

### Create a `UIBinder`

```kotlin
class MyInfoPanelContentBinder : UIBinder {
    override fun bind(viewGroup: ViewGroup): MapboxNavigationObserver {
        val scene = Scene.getSceneForLayout(
            viewGroup,
            R.layout.mapbox_info_panel_content_layout,
            viewGroup.context
        )
        TransitionManager.go(scene, Fade())

        val binding = MapboxInfoPanelContentLayoutBinding.bind(viewGroup)
        return MyInfoPanelContentComponent(binding.content)
    }
}
```

Finally, inject your custom binder to the Drop-In UI.

```kotlin
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.your_activity_layout)

    findViewById<NavigationView>(R.id.navigationView).customizeViewBinders {
        infoPanelContentBinder = MyInfoPanelContentBinder()
    } 
}
```

> **Related content (example): [Inject a custom view to NavigationView](https://docs.mapbox.com/android/navigation/v2/examples/navigation-view-custom-view-injection/)**
> 
> Render custom view to the info panel with `NavigationView`.