Skip to content

Commit 4543b17

Browse files
authored
ignore ime insets in navigation view (#6845)
improve camera layout observer
1 parent 61c5f08 commit 4543b17

File tree

12 files changed

+309
-399
lines changed

12 files changed

+309
-399
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
- Improved `NavigationView` camera behavior to ignore keyboard insets.

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ class NavigationView @JvmOverloads constructor(
134134
backPressedComponent(activity),
135135
scalebarPlaceholderCoordinator(binding.scalebarLayout),
136136
maneuverCoordinator(binding.guidanceLayout),
137-
infoPanelCoordinator(binding.infoPanelLayout, binding.guidelineBottom),
137+
infoPanelCoordinator(binding),
138138
actionButtonsCoordinator(binding.actionListLayout),
139139
speedLimitCoordinator(binding.speedLimitLayout),
140140
roadNameCoordinator(binding.roadNameLayout),

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

Lines changed: 22 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,17 @@ package com.mapbox.navigation.dropin.camera
22

33
import android.content.res.Configuration
44
import android.view.View
5+
import com.google.android.material.bottomsheet.BottomSheetBehavior
56
import com.mapbox.maps.EdgeInsets
67
import com.mapbox.navigation.core.MapboxNavigation
78
import com.mapbox.navigation.dropin.R
89
import com.mapbox.navigation.dropin.databinding.MapboxNavigationViewLayoutBinding
9-
import com.mapbox.navigation.ui.app.internal.Store
10+
import com.mapbox.navigation.dropin.navigationview.NavigationViewContext
1011
import com.mapbox.navigation.ui.app.internal.camera.CameraAction
11-
import com.mapbox.navigation.ui.app.internal.navigation.NavigationState
1212
import com.mapbox.navigation.ui.base.lifecycle.UIComponent
1313

1414
internal class CameraLayoutObserver(
15-
private val store: Store,
15+
private val context: NavigationViewContext,
1616
private val mapView: View,
1717
private val binding: MapboxNavigationViewLayoutBinding,
1818
) : UIComponent() {
@@ -21,63 +21,43 @@ internal class CameraLayoutObserver(
2121
.getDimensionPixelSize(R.dimen.mapbox_camera_overview_padding_v).toDouble()
2222
private val hPadding = binding.root.resources
2323
.getDimensionPixelSize(R.dimen.mapbox_camera_overview_padding_h).toDouble()
24-
private val vPaddingLandscape = binding.root.resources
25-
.getDimensionPixelSize(R.dimen.mapbox_camera_overview_padding_landscape_v).toDouble()
26-
private val hPaddingLandscape = binding.root.resources
27-
.getDimensionPixelSize(R.dimen.mapbox_camera_overview_padding_landscape_h).toDouble()
2824

2925
private val layoutListener = View.OnLayoutChangeListener { _, _, _, _, _, _, _, _, _ ->
30-
val edgeInsets = when (deviceOrientation()) {
31-
Configuration.ORIENTATION_LANDSCAPE -> getLandscapePadding()
32-
else -> getPortraitPadding()
33-
}
34-
store.dispatch(CameraAction.UpdatePadding(edgeInsets))
26+
updateCameraPadding()
3527
}
3628

3729
override fun onAttached(mapboxNavigation: MapboxNavigation) {
3830
super.onAttached(mapboxNavigation)
3931
binding.coordinatorLayout.addOnLayoutChangeListener(layoutListener)
32+
context.behavior.infoPanelBehavior.bottomSheetState.observe { updateCameraPadding() }
4033
}
4134

4235
override fun onDetached(mapboxNavigation: MapboxNavigation) {
4336
super.onDetached(mapboxNavigation)
4437
binding.coordinatorLayout.removeOnLayoutChangeListener(layoutListener)
4538
}
4639

47-
private fun getPortraitPadding(): EdgeInsets {
48-
val top = binding.guidanceLayout.height.toDouble()
49-
val bottom = mapView.height.toDouble() - binding.roadNameLayout.top.toDouble()
50-
return when (store.state.value.navigation) {
51-
is NavigationState.DestinationPreview,
52-
is NavigationState.FreeDrive,
53-
is NavigationState.RoutePreview -> {
54-
EdgeInsets(vPadding, hPadding, bottom, hPadding)
55-
}
56-
is NavigationState.ActiveNavigation,
57-
is NavigationState.Arrival -> {
58-
EdgeInsets(vPadding + top, hPadding, bottom, hPadding)
59-
}
40+
private fun updateCameraPadding() {
41+
val edgeInsets = when (deviceOrientation()) {
42+
Configuration.ORIENTATION_LANDSCAPE -> getLandscapePadding()
43+
else -> getPortraitPadding()
6044
}
45+
context.store.dispatch(CameraAction.UpdatePadding(edgeInsets))
46+
}
47+
48+
private fun getPortraitPadding(): EdgeInsets {
49+
val top = binding.guidanceLayout.bottom
50+
val bottom = mapView.height - binding.roadNameLayout.top
51+
return EdgeInsets(vPadding + top, hPadding, vPadding + bottom, hPadding)
6152
}
6253

6354
private fun getLandscapePadding(): EdgeInsets {
64-
val bottom = mapView.height.toDouble() - binding.roadNameLayout.top.toDouble()
65-
return when (store.state.value.navigation) {
66-
is NavigationState.FreeDrive -> {
67-
EdgeInsets(vPaddingLandscape, hPaddingLandscape, bottom, hPaddingLandscape)
68-
}
69-
is NavigationState.DestinationPreview,
70-
is NavigationState.RoutePreview,
71-
is NavigationState.ActiveNavigation,
72-
is NavigationState.Arrival -> {
73-
EdgeInsets(
74-
vPaddingLandscape,
75-
hPaddingLandscape + binding.infoPanelLayout.right.toDouble(),
76-
bottom,
77-
hPaddingLandscape
78-
)
79-
}
80-
}
55+
val bottomSheetState = context.behavior.infoPanelBehavior.bottomSheetState.value
56+
val isBottomSheetVisible =
57+
bottomSheetState != null && bottomSheetState != BottomSheetBehavior.STATE_HIDDEN
58+
val bottomSheetWidth = if (isBottomSheetVisible) binding.infoPanelLayout.right else 0
59+
val bottom = mapView.height - binding.roadNameLayout.top
60+
return EdgeInsets(vPadding, hPadding + bottomSheetWidth, vPadding + bottom, hPadding)
8161
}
8262

8363
private fun deviceOrientation() = binding.root.resources.configuration.orientation

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

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@ package com.mapbox.navigation.dropin.infopanel
33
import android.view.View
44
import android.view.ViewGroup
55
import android.view.ViewTreeObserver
6-
import androidx.constraintlayout.widget.Guideline
76
import androidx.core.graphics.Insets
87
import androidx.core.view.ViewCompat
98
import com.google.android.material.bottomsheet.BottomSheetBehavior
109
import com.mapbox.navigation.core.MapboxNavigation
10+
import com.mapbox.navigation.dropin.databinding.MapboxNavigationViewLayoutBinding
1111
import com.mapbox.navigation.dropin.navigationview.NavigationViewContext
1212
import com.mapbox.navigation.ui.app.internal.navigation.NavigationState
1313
import com.mapbox.navigation.ui.base.lifecycle.UIBinder
@@ -27,11 +27,10 @@ import kotlinx.coroutines.launch
2727
*/
2828
internal class InfoPanelCoordinator(
2929
private val context: NavigationViewContext,
30-
private val infoPanel: ViewGroup,
31-
private val guidelineBottom: Guideline
32-
) : UICoordinator<ViewGroup>(infoPanel) {
30+
private val binding: MapboxNavigationViewLayoutBinding,
31+
) : UICoordinator<ViewGroup>(binding.infoPanelLayout) {
3332
private val store = context.store
34-
private val behavior = BottomSheetBehavior.from(infoPanel)
33+
private val behavior = BottomSheetBehavior.from(binding.infoPanelLayout)
3534

3635
private val updateGuideline = object : BottomSheetBehavior.BottomSheetCallback() {
3736
override fun onStateChanged(bottomSheet: View, newState: Int) {
@@ -48,22 +47,23 @@ internal class InfoPanelCoordinator(
4847
@OptIn(ExperimentalCoroutinesApi::class)
4948
private val infoPanelTop = callbackFlow {
5049
val onGlobalLayoutListener = ViewTreeObserver.OnGlobalLayoutListener {
51-
trySend(infoPanel.top)
50+
trySend(binding.infoPanelLayout.top)
5251
}
53-
val viewTreeObserver = infoPanel.viewTreeObserver
52+
val viewTreeObserver = binding.infoPanelLayout.viewTreeObserver
5453
viewTreeObserver.addOnGlobalLayoutListener(onGlobalLayoutListener)
5554
awaitClose { viewTreeObserver.removeOnGlobalLayoutListener(onGlobalLayoutListener) }
5655
}.distinctUntilChanged()
5756

5857
init {
59-
infoPanel.addOnLayoutChangeListener(FixBottomSheetLayoutWhenHidden(infoPanel, behavior))
58+
binding.infoPanelLayout.addOnLayoutChangeListener(FixBottomSheetLayoutWhenHidden())
6059
behavior.peekHeight = context.styles.infoPanelPeekHeight.value
6160
behavior.hide()
6261
}
6362

6463
override fun onAttached(mapboxNavigation: MapboxNavigation) {
6564
super.onAttached(mapboxNavigation)
6665

66+
context.behavior.infoPanelBehavior.updateBottomSheetState(behavior.state)
6767
behavior.addBottomSheetCallback(updateGuideline)
6868
coroutineScope.launch {
6969
bottomSheetState().collect { state ->
@@ -79,7 +79,10 @@ internal class InfoPanelCoordinator(
7979
}
8080
}
8181
coroutineScope.launch {
82-
context.systemBarsInsets.collect { updateGuidelinePosition(systemBarsInsets = it) }
82+
context.systemBarsInsets.collect { insets ->
83+
binding.container.setPadding(insets.left, insets.top, insets.right, insets.bottom)
84+
updateGuidelinePosition(systemBarsInsets = insets)
85+
}
8386
}
8487
coroutineScope.launch {
8588
context.styles.infoPanelGuidelineMaxPosPercent.collect {
@@ -162,14 +165,14 @@ internal class InfoPanelCoordinator(
162165

163166
private fun updateGuidelinePosition(
164167
systemBarsInsets: Insets = context.systemBarsInsets.value,
165-
infoPanelTop: Int = infoPanel.top,
168+
infoPanelTop: Int = binding.infoPanelLayout.top,
166169
maxPosPercent: Float = context.styles.infoPanelGuidelineMaxPosPercent.value
167170
) {
168-
val parentHeight = (infoPanel.parent as ViewGroup).height
171+
val parentHeight = binding.coordinatorLayout.height
169172
val maxPos = (parentHeight * maxPosPercent).toInt() - systemBarsInsets.bottom
170173
if (0 < maxPos) {
171174
val pos = parentHeight - infoPanelTop - systemBarsInsets.bottom
172-
guidelineBottom.setGuidelineEnd(pos.coerceIn(0, maxPos))
175+
binding.guidelineBottom.setGuidelineEnd(pos.coerceIn(0, maxPos))
173176
}
174177
}
175178

@@ -193,10 +196,7 @@ internal class InfoPanelCoordinator(
193196
* An OnLayoutChangeListener that ensures the bottom sheet is always laid out at the bottom of
194197
* the parent view when in STATE_HIDDEN.
195198
*/
196-
private class FixBottomSheetLayoutWhenHidden(
197-
private val layout: ViewGroup,
198-
private val behavior: BottomSheetBehavior<ViewGroup>
199-
) : View.OnLayoutChangeListener {
199+
private inner class FixBottomSheetLayoutWhenHidden : View.OnLayoutChangeListener {
200200

201201
override fun onLayoutChange(
202202
v: View?,
@@ -210,7 +210,10 @@ internal class InfoPanelCoordinator(
210210
oldBottom: Int
211211
) {
212212
if (behavior.state == BottomSheetBehavior.STATE_HIDDEN) {
213-
ViewCompat.offsetTopAndBottom(layout, (layout.parent as? View)?.height ?: 0)
213+
ViewCompat.offsetTopAndBottom(
214+
binding.infoPanelLayout,
215+
binding.coordinatorLayout.height,
216+
)
214217
}
215218
}
216219
}

libnavui-dropin/src/main/java/com/mapbox/navigation/dropin/internal/extensions/NavigationViewContextEx.kt

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ package com.mapbox.navigation.dropin.internal.extensions
55
import android.view.ViewGroup
66
import androidx.activity.ComponentActivity
77
import androidx.annotation.Px
8-
import androidx.constraintlayout.widget.Guideline
98
import com.mapbox.maps.MapView
109
import com.mapbox.maps.plugin.locationcomponent.location
1110
import com.mapbox.navigation.core.MapboxNavigation
@@ -269,9 +268,8 @@ internal fun NavigationViewContext.maneuverCoordinator(guidanceLayout: ViewGroup
269268
ManeuverCoordinator(this, guidanceLayout)
270269

271270
internal fun NavigationViewContext.infoPanelCoordinator(
272-
infoPanelLayout: ViewGroup,
273-
guidelineBottom: Guideline
274-
) = InfoPanelCoordinator(this, infoPanelLayout, guidelineBottom)
271+
binding: MapboxNavigationViewLayoutBinding,
272+
) = InfoPanelCoordinator(this, binding)
275273

276274
internal fun NavigationViewContext.actionButtonsCoordinator(actionListLayout: ViewGroup) =
277275
ActionButtonsCoordinator(this, actionListLayout)

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ abstract class MapViewBinder : UIBinder {
6767
val store = context.store
6868
val navigationState = store.select { it.navigation }
6969
return navigationListOf(
70-
CameraLayoutObserver(store, mapView, navigationViewBinding),
70+
CameraLayoutObserver(context, mapView, navigationViewBinding),
7171
LocationComponent(context.locationProvider),
7272
context.locationPuckComponent(mapView),
7373
LogoAttributionComponent(mapView, context.systemBarsInsets),

0 commit comments

Comments
 (0)