Skip to content

Commit b6d4666

Browse files
committed
add the ability to show/hide scalebar
1 parent 24cb06d commit b6d4666

23 files changed

Lines changed: 894 additions & 5 deletions

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ Mapbox welcomes participation and contributions from everyone.
2222
- Improved stop detector for auto profile. [#6373](https://github.com/mapbox/mapbox-navigation-android/pull/6373)
2323
- Fixed `RoadNameLabel` position issues by making sure that it updates when expanding and collapsing the info panel. [#6361](https://github.com/mapbox/mapbox-navigation-android/pull/6361)
2424
- Fixed `InfoPanel` overlapping the `RoadNameLabel` in free drive state with the device being in landscape orientation. [#6361](https://github.com/mapbox/mapbox-navigation-android/pull/6361)
25+
- Introduced `ViewStyleCustomization#mapScalebarParams` that allows for configuring map scalebar. [#6355](https://github.com/mapbox/mapbox-navigation-android/pull/6355)
2526

2627
## Mapbox Navigation SDK 2.9.0-alpha.2 - 16 September, 2022
2728
### Changelog

libnavui-dropin/api/current.txt

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,20 @@ package com.mapbox.navigation.dropin {
2828
property public final int style;
2929
}
3030

31+
public final class MapboxMapScalebarParams {
32+
method public boolean getEnabled();
33+
method public boolean isMetricUnits();
34+
property public final boolean enabled;
35+
property public final boolean isMetricUnits;
36+
}
37+
38+
public static final class MapboxMapScalebarParams.Builder {
39+
ctor public MapboxMapScalebarParams.Builder(android.content.Context context);
40+
method public com.mapbox.navigation.dropin.MapboxMapScalebarParams build();
41+
method public com.mapbox.navigation.dropin.MapboxMapScalebarParams.Builder enabled(boolean enabled);
42+
method public com.mapbox.navigation.dropin.MapboxMapScalebarParams.Builder isMetricsUnits(Boolean? isMetricUnits);
43+
}
44+
3145
@com.mapbox.navigation.base.ExperimentalPreviewMapboxNavigationAPI public final class NavigationView extends android.widget.FrameLayout implements androidx.lifecycle.LifecycleOwner {
3246
ctor public NavigationView(android.content.Context context, android.util.AttributeSet? attrs = null, String accessToken = attrs.navigationViewAccessToken(context), androidx.lifecycle.ViewModelStoreOwner viewModelStoreOwner = context.toViewModelStoreOwner());
3347
ctor public NavigationView(android.content.Context context, android.util.AttributeSet? attrs = null, String accessToken = attrs.navigationViewAccessToken(context));
@@ -220,6 +234,7 @@ package com.mapbox.navigation.dropin {
220234
method public Integer? getInfoPanelPeekHeight();
221235
method public com.mapbox.maps.plugin.LocationPuck? getLocationPuck();
222236
method public com.mapbox.navigation.ui.maneuver.model.ManeuverViewOptions? getManeuverViewOptions();
237+
method public com.mapbox.navigation.dropin.MapboxMapScalebarParams? getMapScalebarParams();
223238
method public Integer? getPoiNameTextAppearance();
224239
method public com.mapbox.navigation.dropin.MapboxExtendableButtonParams? getRecenterButtonParams();
225240
method public Integer? getRoadNameBackground();
@@ -240,6 +255,7 @@ package com.mapbox.navigation.dropin {
240255
method public void setInfoPanelPeekHeight(Integer?);
241256
method public void setLocationPuck(com.mapbox.maps.plugin.LocationPuck?);
242257
method public void setManeuverViewOptions(com.mapbox.navigation.ui.maneuver.model.ManeuverViewOptions?);
258+
method public void setMapScalebarParams(com.mapbox.navigation.dropin.MapboxMapScalebarParams?);
243259
method public void setPoiNameTextAppearance(Integer?);
244260
method public void setRecenterButtonParams(com.mapbox.navigation.dropin.MapboxExtendableButtonParams?);
245261
method public void setRoadNameBackground(Integer?);
@@ -260,6 +276,7 @@ package com.mapbox.navigation.dropin {
260276
property public final Integer? infoPanelPeekHeight;
261277
property public final com.mapbox.maps.plugin.LocationPuck? locationPuck;
262278
property public final com.mapbox.navigation.ui.maneuver.model.ManeuverViewOptions? maneuverViewOptions;
279+
property public final com.mapbox.navigation.dropin.MapboxMapScalebarParams? mapScalebarParams;
263280
property public final Integer? poiNameTextAppearance;
264281
property public final com.mapbox.navigation.dropin.MapboxExtendableButtonParams? recenterButtonParams;
265282
property public final Integer? roadNameBackground;
@@ -284,6 +301,7 @@ package com.mapbox.navigation.dropin {
284301
method @Px public int defaultInfoPanelPeekHeight(android.content.Context context);
285302
method public com.mapbox.maps.plugin.LocationPuck defaultLocationPuck(android.content.Context context);
286303
method public com.mapbox.navigation.ui.maneuver.model.ManeuverViewOptions defaultManeuverViewOptions();
304+
method public com.mapbox.navigation.dropin.MapboxMapScalebarParams defaultMapScalebarParams(android.content.Context context);
287305
method @StyleRes public int defaultPoiNameTextAppearance();
288306
method public com.mapbox.navigation.dropin.MapboxExtendableButtonParams defaultRecenterButtonParams(android.content.Context context);
289307
method @DrawableRes public int defaultRoadNameBackground();
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
package com.mapbox.navigation.dropin
2+
3+
import android.content.Context
4+
import com.mapbox.navigation.base.formatter.UnitType
5+
import com.mapbox.navigation.base.internal.extensions.LocaleEx.getUnitTypeForLocale
6+
import com.mapbox.navigation.base.internal.extensions.inferDeviceLocale
7+
8+
/**
9+
* Params describing the map scalebar config.
10+
*
11+
* @param enabled true if the scalebar should be shown on the map, false otherwise
12+
* @param isMetricUnits true if the scale bar is using metric system,
13+
* false if the scale bar is using imperial units.
14+
*/
15+
class MapboxMapScalebarParams private constructor(
16+
val enabled: Boolean,
17+
val isMetricUnits: Boolean,
18+
) {
19+
20+
/**
21+
* Indicates whether some other object is "equal to" this one.
22+
*/
23+
override fun equals(other: Any?): Boolean {
24+
if (this === other) return true
25+
if (javaClass != other?.javaClass) return false
26+
27+
other as MapboxMapScalebarParams
28+
29+
if (enabled != other.enabled) return false
30+
if (isMetricUnits != other.isMetricUnits) return false
31+
32+
return true
33+
}
34+
35+
/**
36+
* Returns a hash code value for the object.
37+
*/
38+
override fun hashCode(): Int {
39+
var result = enabled.hashCode()
40+
result = 31 * result + isMetricUnits.hashCode()
41+
return result
42+
}
43+
44+
/**
45+
* Returns a string representation of the object.
46+
*/
47+
override fun toString(): String {
48+
return "MapboxMapScalebarParams(" +
49+
"enabled=$enabled, " +
50+
"isMetricUnits=$isMetricUnits" +
51+
")"
52+
}
53+
54+
/**
55+
* Builder for [MapboxMapScalebarParams].
56+
*/
57+
class Builder(context: Context) {
58+
59+
private val applicationContext = context.applicationContext
60+
private var enabled: Boolean = false
61+
private var isMetricsUnits: Boolean? = null
62+
63+
/**
64+
* Whether to show the scalebar on the map.
65+
* @param enabled true if the scalebar should be shown on the map, false otherwise
66+
* @return the same builder object
67+
*/
68+
fun enabled(enabled: Boolean): Builder = apply {
69+
this.enabled = enabled
70+
}
71+
72+
/**
73+
* Whether the scale bar is using metric unit.
74+
* @param isMetricUnits true if the scale bar is using metric system,
75+
* false if the scale bar is using imperial units.
76+
* @return the same builder object
77+
*/
78+
fun isMetricsUnits(isMetricUnits: Boolean?): Builder = apply {
79+
this.isMetricsUnits = isMetricUnits
80+
}
81+
82+
/**
83+
* Create a [MapboxMapScalebarParams] object.
84+
* @return [MapboxMapScalebarParams]
85+
*/
86+
fun build(): MapboxMapScalebarParams {
87+
return MapboxMapScalebarParams(
88+
enabled,
89+
isMetricsUnits ?: getDefaultIsMetricUnits()
90+
)
91+
}
92+
93+
private fun getDefaultIsMetricUnits(): Boolean {
94+
val unitType = applicationContext.inferDeviceLocale().getUnitTypeForLocale()
95+
return when (unitType) {
96+
UnitType.IMPERIAL -> false
97+
UnitType.METRIC -> true
98+
}
99+
}
100+
}
101+
}

libnavui-dropin/src/main/java/com/mapbox/navigation/dropin/NavigationView.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import com.mapbox.navigation.dropin.coordinator.ManeuverCoordinator
3232
import com.mapbox.navigation.dropin.coordinator.MapLayoutCoordinator
3333
import com.mapbox.navigation.dropin.coordinator.RightFrameCoordinator
3434
import com.mapbox.navigation.dropin.coordinator.RoadNameLabelCoordinator
35+
import com.mapbox.navigation.dropin.coordinator.ScalebarPlaceholderCoordinator
3536
import com.mapbox.navigation.dropin.coordinator.SpeedLimitCoordinator
3637
import com.mapbox.navigation.dropin.databinding.MapboxNavigationViewLayoutBinding
3738
import com.mapbox.navigation.dropin.internal.MapboxNavigationViewApi
@@ -129,6 +130,7 @@ class NavigationView @JvmOverloads constructor(
129130
this,
130131
navigationContext.listenerRegistry
131132
),
133+
ScalebarPlaceholderCoordinator(navigationContext, binding.scalebarLayout),
132134
ManeuverCoordinator(navigationContext, binding.guidanceLayout),
133135
InfoPanelCoordinator(
134136
navigationContext,

libnavui-dropin/src/main/java/com/mapbox/navigation/dropin/NavigationViewStyles.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@ internal class NavigationViewStyles(context: Context) {
5252
MutableStateFlow(ViewStyleCustomization.defaultArrivalTextAppearance())
5353
private val _locationPuck: MutableStateFlow<LocationPuck> =
5454
MutableStateFlow(ViewStyleCustomization.defaultLocationPuck(context))
55+
private val _mapScalebarParams: MutableStateFlow<MapboxMapScalebarParams> = MutableStateFlow(
56+
ViewStyleCustomization.defaultMapScalebarParams(context)
57+
)
5558

5659
val infoPanelPeekHeight: StateFlow<Int> = _infoPanelPeekHeight.asStateFlow()
5760
val infoPanelMarginStart: StateFlow<Int> = _infoPanelMarginStart.asStateFlow()
@@ -80,6 +83,7 @@ internal class NavigationViewStyles(context: Context) {
8083
val maneuverViewOptions: StateFlow<ManeuverViewOptions> = _maneuverViewOptions.asStateFlow()
8184
val arrivalTextAppearance: StateFlow<Int> = _arrivalTextAppearance.asStateFlow()
8285
val locationPuck: StateFlow<LocationPuck> = _locationPuck.asStateFlow()
86+
val mapScalebarParams: StateFlow<MapboxMapScalebarParams> = _mapScalebarParams.asStateFlow()
8387

8488
fun applyCustomization(customization: ViewStyleCustomization) {
8589
customization.infoPanelPeekHeight?.also { _infoPanelPeekHeight.value = it }
@@ -104,5 +108,6 @@ internal class NavigationViewStyles(context: Context) {
104108
customization.roadNameTextAppearance?.also { _roadNameTextAppearance.value = it }
105109
customization.arrivalTextAppearance?.also { _arrivalTextAppearance.value = it }
106110
customization.locationPuck?.also { _locationPuck.value = it }
111+
customization.mapScalebarParams?.also { _mapScalebarParams.value = it }
107112
}
108113
}

libnavui-dropin/src/main/java/com/mapbox/navigation/dropin/ViewStyleCustomization.kt

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,16 @@ class ViewStyleCustomization {
168168
*/
169169
var locationPuck: LocationPuck? = null
170170

171+
/**
172+
* Map scalebar params.
173+
* Use [defaultMapScalebarParams] to reset to default.
174+
* NOTE: When `enabled`, the `scalebar` will always be added to the top start corner
175+
* of the screen. Position of the `scalebar` using `NavigationView` cannot be changed at any
176+
* given time. However, if you change the position using `MapView`, the behavior is undefined
177+
* and you will be responsible to ensure the correct positioning based on other view overlays.
178+
*/
179+
var mapScalebarParams: MapboxMapScalebarParams? = null
180+
171181
companion object {
172182
/**
173183
* Default info panel peek height in pixels.
@@ -375,6 +385,12 @@ class ViewStyleCustomization {
375385
)
376386
)
377387

388+
/**
389+
* Default map scalebar parameters.
390+
*/
391+
fun defaultMapScalebarParams(context: Context): MapboxMapScalebarParams =
392+
MapboxMapScalebarParams.Builder(context).build()
393+
378394
private fun Context.defaultSpacing() =
379395
resources.getDimensionPixelSize(R.dimen.mapbox_actionList_spacing)
380396

libnavui-dropin/src/main/java/com/mapbox/navigation/dropin/binder/map/MapBinder.kt

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import com.mapbox.geojson.Point
55
import com.mapbox.maps.MapView
66
import com.mapbox.maps.plugin.compass.compass
77
import com.mapbox.maps.plugin.locationcomponent.location
8-
import com.mapbox.maps.plugin.scalebar.scalebar
98
import com.mapbox.navigation.base.ExperimentalPreviewMapboxNavigationAPI
109
import com.mapbox.navigation.base.route.NavigationRoute
1110
import com.mapbox.navigation.core.MapboxNavigation
@@ -15,6 +14,7 @@ import com.mapbox.navigation.dropin.NavigationViewContext
1514
import com.mapbox.navigation.dropin.component.camera.CameraComponent
1615
import com.mapbox.navigation.dropin.component.camera.CameraLayoutObserver
1716
import com.mapbox.navigation.dropin.component.logo.LogoAttributionComponent
17+
import com.mapbox.navigation.dropin.component.map.ScalebarComponent
1818
import com.mapbox.navigation.dropin.component.marker.FreeDriveLongPressMapComponent
1919
import com.mapbox.navigation.dropin.component.marker.GeocodingComponent
2020
import com.mapbox.navigation.dropin.component.marker.MapMarkersComponent
@@ -48,9 +48,14 @@ internal class MapBinder(
4848

4949
init {
5050
mapView.compass.enabled = false
51-
mapView.scalebar.enabled = false
5251
}
5352

53+
private val scalebarComponent = ScalebarComponent(
54+
mapView,
55+
context.styles.mapScalebarParams,
56+
context.systemBarsInsets
57+
)
58+
5459
private val store = context.store
5560

5661
override fun bind(viewGroup: ViewGroup): MapboxNavigationObserver {
@@ -86,7 +91,8 @@ internal class MapBinder(
8691
navigationState
8792
) { _, arrowOptions, navState ->
8893
routeArrowComponent(navState, arrowOptions)
89-
}
94+
},
95+
scalebarComponent
9096
)
9197
}
9298

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package com.mapbox.navigation.dropin.component.map
2+
3+
import android.view.Gravity
4+
import androidx.core.graphics.Insets
5+
import com.mapbox.maps.MapView
6+
import com.mapbox.maps.plugin.scalebar.scalebar
7+
import com.mapbox.navigation.base.ExperimentalPreviewMapboxNavigationAPI
8+
import com.mapbox.navigation.core.MapboxNavigation
9+
import com.mapbox.navigation.dropin.MapboxMapScalebarParams
10+
import com.mapbox.navigation.ui.base.lifecycle.UIComponent
11+
import kotlinx.coroutines.flow.StateFlow
12+
13+
@ExperimentalPreviewMapboxNavigationAPI
14+
internal class ScalebarComponent(
15+
private val mapView: MapView,
16+
private val scalebarParams: StateFlow<MapboxMapScalebarParams>,
17+
private val systemBarInsets: StateFlow<Insets>,
18+
) : UIComponent() {
19+
20+
private val defaultMarginTop = 4f
21+
private val defaultMarginLeft = 4f
22+
23+
init {
24+
setUpScalebar(scalebarParams.value)
25+
mapView.scalebar.updateSettings {
26+
position = Gravity.TOP or Gravity.START
27+
// temporary workaround, remove after MAPSMBL-173
28+
textBorderWidth = 3f
29+
}
30+
}
31+
32+
override fun onAttached(mapboxNavigation: MapboxNavigation) {
33+
super.onAttached(mapboxNavigation)
34+
scalebarParams.observe { setUpScalebar(it) }
35+
systemBarInsets.observe { insets ->
36+
mapView.scalebar.updateSettings {
37+
marginTop = defaultMarginTop + insets.top
38+
marginLeft = defaultMarginLeft + insets.left
39+
}
40+
}
41+
}
42+
43+
private fun setUpScalebar(params: MapboxMapScalebarParams) {
44+
mapView.scalebar.updateSettings {
45+
enabled = params.enabled
46+
isMetricUnits = params.isMetricUnits
47+
}
48+
}
49+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package com.mapbox.navigation.dropin.component.map
2+
3+
import android.view.View
4+
import com.mapbox.navigation.base.ExperimentalPreviewMapboxNavigationAPI
5+
import com.mapbox.navigation.core.MapboxNavigation
6+
import com.mapbox.navigation.dropin.MapboxMapScalebarParams
7+
import com.mapbox.navigation.ui.app.internal.State
8+
import com.mapbox.navigation.ui.app.internal.navigation.NavigationState
9+
import com.mapbox.navigation.ui.base.lifecycle.UIComponent
10+
import kotlinx.coroutines.flow.Flow
11+
import kotlinx.coroutines.flow.StateFlow
12+
import kotlinx.coroutines.flow.collect
13+
import kotlinx.coroutines.flow.combine
14+
import kotlinx.coroutines.launch
15+
16+
@ExperimentalPreviewMapboxNavigationAPI
17+
internal class ScalebarPlaceholderComponent(
18+
private val scalebarPlaceholder: View,
19+
private val scalebarParams: StateFlow<MapboxMapScalebarParams>,
20+
private val navigationState: StateFlow<State>,
21+
) : UIComponent() {
22+
23+
override fun onAttached(mapboxNavigation: MapboxNavigation) {
24+
super.onAttached(mapboxNavigation)
25+
coroutineScope.launch {
26+
combine(scalebarParams, navigationState) { params, state ->
27+
scalebarPlaceholder.visibility =
28+
if (params.enabled && state.navigation !is NavigationState.ActiveNavigation) {
29+
View.VISIBLE
30+
} else {
31+
View.GONE
32+
}
33+
}.collect()
34+
}
35+
}
36+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package com.mapbox.navigation.dropin.coordinator
2+
3+
import android.view.View
4+
import android.view.ViewGroup
5+
import com.mapbox.navigation.base.ExperimentalPreviewMapboxNavigationAPI
6+
import com.mapbox.navigation.core.lifecycle.MapboxNavigationObserver
7+
import com.mapbox.navigation.dropin.NavigationViewContext
8+
import com.mapbox.navigation.dropin.R
9+
import com.mapbox.navigation.dropin.component.map.ScalebarPlaceholderComponent
10+
import com.mapbox.navigation.dropin.databinding.MapboxScalebarPlaceholderLayoutBinding
11+
import com.mapbox.navigation.ui.app.internal.extension.actionsFlowable
12+
import com.mapbox.navigation.ui.base.lifecycle.UIBinder
13+
import kotlinx.coroutines.flow.map
14+
15+
@OptIn(ExperimentalPreviewMapboxNavigationAPI::class)
16+
internal class ScalebarPlaceholderBinder(
17+
private val context: NavigationViewContext,
18+
) : UIBinder {
19+
20+
override fun bind(viewGroup: ViewGroup): MapboxNavigationObserver {
21+
val binding = inflateLayout(viewGroup)
22+
return ScalebarPlaceholderComponent(
23+
binding.scalebarPlaceholder,
24+
context.styles.mapScalebarParams,
25+
context.store.state
26+
)
27+
}
28+
29+
private fun inflateLayout(viewGroup: ViewGroup): MapboxScalebarPlaceholderLayoutBinding {
30+
viewGroup.removeAllViews()
31+
View.inflate(viewGroup.context, R.layout.mapbox_scalebar_placeholder_layout, viewGroup)
32+
return MapboxScalebarPlaceholderLayoutBinding.bind(viewGroup)
33+
}
34+
}

0 commit comments

Comments
 (0)