Skip to content

Commit bd5c950

Browse files
committed
ignore ime insets in navigation view
1 parent ce11135 commit bd5c950

7 files changed

Lines changed: 230 additions & 253 deletions

File tree

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/infopanel/InfoPanelCoordinator.kt

Lines changed: 19 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,15 +47,15 @@ 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
}
@@ -79,7 +78,10 @@ internal class InfoPanelCoordinator(
7978
}
8079
}
8180
coroutineScope.launch {
82-
context.systemBarsInsets.collect { updateGuidelinePosition(systemBarsInsets = it) }
81+
context.systemBarsInsets.collect { insets ->
82+
binding.container.setPadding(insets.left, insets.top, insets.right, insets.bottom)
83+
updateGuidelinePosition(systemBarsInsets = insets)
84+
}
8385
}
8486
coroutineScope.launch {
8587
context.styles.infoPanelGuidelineMaxPosPercent.collect {
@@ -162,14 +164,14 @@ internal class InfoPanelCoordinator(
162164

163165
private fun updateGuidelinePosition(
164166
systemBarsInsets: Insets = context.systemBarsInsets.value,
165-
infoPanelTop: Int = infoPanel.top,
167+
infoPanelTop: Int = binding.infoPanelLayout.top,
166168
maxPosPercent: Float = context.styles.infoPanelGuidelineMaxPosPercent.value
167169
) {
168-
val parentHeight = (infoPanel.parent as ViewGroup).height
170+
val parentHeight = binding.coordinatorLayout.height
169171
val maxPos = (parentHeight * maxPosPercent).toInt() - systemBarsInsets.bottom
170172
if (0 < maxPos) {
171173
val pos = parentHeight - infoPanelTop - systemBarsInsets.bottom
172-
guidelineBottom.setGuidelineEnd(pos.coerceIn(0, maxPos))
174+
binding.guidelineBottom.setGuidelineEnd(pos.coerceIn(0, maxPos))
173175
}
174176
}
175177

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

201200
override fun onLayoutChange(
202201
v: View?,
@@ -210,7 +209,10 @@ internal class InfoPanelCoordinator(
210209
oldBottom: Int
211210
) {
212211
if (behavior.state == BottomSheetBehavior.STATE_HIDDEN) {
213-
ViewCompat.offsetTopAndBottom(layout, (layout.parent as? View)?.height ?: 0)
212+
ViewCompat.offsetTopAndBottom(
213+
binding.infoPanelLayout,
214+
binding.coordinatorLayout.height,
215+
)
214216
}
215217
}
216218
}

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/res/layout-land/mapbox_navigation_view_layout.xml

Lines changed: 107 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -13,131 +13,121 @@
1313
tools:background="#00ccff" />
1414

1515
<!--
16-
Using outer CoordinatorLayout to adjust inner CoordinatorLayout layout based on system
17-
windows such as the status bar and the navigation bar.
1816
CoordinatorLayout allows customization of navigation bar color using android:statusBarColor
1917
theme attribute, while FrameLayout doesn't.
2018
-->
2119
<androidx.coordinatorlayout.widget.CoordinatorLayout
20+
android:id="@+id/coordinatorLayout"
2221
android:layout_width="match_parent"
2322
android:layout_height="match_parent">
2423

25-
<androidx.coordinatorlayout.widget.CoordinatorLayout
26-
android:id="@+id/coordinatorLayout"
24+
<androidx.constraintlayout.widget.ConstraintLayout
25+
android:id="@+id/container"
2726
android:layout_width="match_parent"
28-
android:layout_height="match_parent"
29-
android:fitsSystemWindows="true">
30-
31-
<androidx.constraintlayout.widget.ConstraintLayout
32-
android:id="@+id/container"
33-
android:layout_width="match_parent"
34-
android:layout_height="match_parent">
35-
36-
<androidx.constraintlayout.widget.Guideline
37-
android:id="@+id/guidelineBottom"
38-
android:orientation="horizontal"
39-
android:layout_width="wrap_content"
40-
android:layout_height="wrap_content"
41-
app:layout_constraintGuide_end="0dp"
42-
tools:layout_constraintGuide_end="100dp" />
43-
44-
<androidx.constraintlayout.widget.Guideline
45-
android:id="@+id/guidelineBegin"
46-
android:orientation="vertical"
47-
android:layout_width="wrap_content"
48-
android:layout_height="wrap_content"
49-
app:layout_constraintGuide_begin="375dp"
50-
tools:layout_constraintGuide_begin="375dp" />
51-
52-
<FrameLayout
53-
android:id="@+id/guidanceLayout"
54-
android:layout_width="wrap_content"
55-
android:layout_height="0dp"
56-
app:layout_constraintTop_toTopOf="parent"
57-
app:layout_constraintStart_toStartOf="parent"
58-
tools:layout_height="120dp"
59-
tools:background="@color/mapbox_main_maneuver_background_color" />
60-
61-
<FrameLayout
62-
android:id="@+id/scalebarLayout"
63-
android:layout_width="wrap_content"
64-
android:layout_height="wrap_content"
65-
app:layout_constraintTop_toTopOf="parent"
66-
app:layout_constraintStart_toStartOf="@id/guidanceLayout"
67-
/>
68-
69-
<FrameLayout
70-
android:id="@+id/speedLimitLayout"
71-
android:layout_width="75dp"
72-
android:layout_height="wrap_content"
73-
android:layout_marginStart="4dp"
74-
android:layout_marginTop="8dp"
75-
app:layout_constraintStart_toEndOf="@id/guidanceLayout"
76-
app:layout_constraintTop_toBottomOf="@id/scalebarLayout"
77-
tools:background="#eee"
78-
tools:layout_height="60dp"
79-
tools:layout_width="50dp"
80-
android:layout_gravity="start|top" />
81-
82-
<FrameLayout
83-
android:id="@+id/emptyLeftContainer"
84-
android:layout_width="0dp"
85-
android:layout_height="0dp"
86-
android:layout_marginStart="4dp"
87-
android:layout_marginTop="8dp"
88-
android:layout_marginBottom="8dp"
89-
app:layout_constraintStart_toStartOf="parent"
90-
app:layout_constraintTop_toBottomOf="@id/speedLimitLayout"
91-
app:layout_constraintBottom_toTopOf="@id/guidelineBottom"
92-
app:layout_constraintEnd_toStartOf="@id/guidelineBegin"
93-
tools:background="#F6A1A1"
94-
android:layout_gravity="start|top" />
95-
96-
<FrameLayout
97-
android:id="@+id/emptyRightContainer"
98-
android:layout_width="wrap_content"
99-
android:layout_height="wrap_content"
100-
android:layout_marginEnd="4dp"
101-
android:layout_marginTop="8dp"
102-
android:layout_marginBottom="8dp"
103-
android:layout_marginStart="4dp"
104-
app:layout_constraintEnd_toEndOf="parent"
105-
app:layout_constraintTop_toBottomOf="@id/actionListLayout"
106-
app:layout_constraintBottom_toTopOf="@id/roadNameLayout"
107-
tools:background="#F6A1A1"
108-
tools:layout_height="130dp"
109-
tools:layout_width="76dp"
110-
android:layout_gravity="start|top" />
111-
112-
<FrameLayout
113-
android:id="@+id/actionListLayout"
114-
android:layout_width="@dimen/mapbox_actionList_width"
115-
android:layout_height="wrap_content"
116-
android:gravity="top|right"
117-
android:layout_marginEnd="8dp"
118-
android:layout_marginTop="5dp"
119-
app:layout_constraintTop_toTopOf="parent"
120-
app:layout_constraintEnd_toEndOf="parent"
121-
tools:layout_height="200dp"
122-
tools:background="#eee" />
123-
124-
<FrameLayout
125-
android:id="@+id/roadNameLayout"
126-
android:layout_width="wrap_content"
127-
android:layout_height="0dp"
128-
android:layout_gravity="center"
129-
tools:background="#eee"
130-
tools:layout_height="52dp"
131-
tools:layout_width="140dp"
132-
app:layout_constraintBottom_toBottomOf="parent"
133-
app:layout_constraintEnd_toEndOf="parent"
134-
app:layout_constraintStart_toStartOf="parent"
135-
android:layout_marginBottom="8dp"
136-
app:layout_constraintHeight_max="62dp" />
137-
138-
</androidx.constraintlayout.widget.ConstraintLayout>
139-
140-
</androidx.coordinatorlayout.widget.CoordinatorLayout>
27+
android:layout_height="match_parent">
28+
29+
<androidx.constraintlayout.widget.Guideline
30+
android:id="@+id/guidelineBottom"
31+
android:layout_width="wrap_content"
32+
android:layout_height="wrap_content"
33+
android:orientation="horizontal"
34+
app:layout_constraintGuide_end="0dp"
35+
tools:layout_constraintGuide_end="100dp" />
36+
37+
<androidx.constraintlayout.widget.Guideline
38+
android:id="@+id/guidelineBegin"
39+
android:layout_width="wrap_content"
40+
android:layout_height="wrap_content"
41+
android:orientation="vertical"
42+
app:layout_constraintGuide_begin="375dp"
43+
tools:layout_constraintGuide_begin="375dp" />
44+
45+
<FrameLayout
46+
android:id="@+id/guidanceLayout"
47+
android:layout_width="wrap_content"
48+
android:layout_height="0dp"
49+
app:layout_constraintStart_toStartOf="parent"
50+
app:layout_constraintTop_toTopOf="parent"
51+
tools:background="@color/mapbox_main_maneuver_background_color"
52+
tools:layout_height="120dp" />
53+
54+
<FrameLayout
55+
android:id="@+id/scalebarLayout"
56+
android:layout_width="wrap_content"
57+
android:layout_height="wrap_content"
58+
app:layout_constraintStart_toStartOf="@id/guidanceLayout"
59+
app:layout_constraintTop_toTopOf="parent" />
60+
61+
<FrameLayout
62+
android:id="@+id/speedLimitLayout"
63+
android:layout_width="75dp"
64+
android:layout_height="wrap_content"
65+
android:layout_gravity="start|top"
66+
android:layout_marginStart="4dp"
67+
android:layout_marginTop="8dp"
68+
app:layout_constraintStart_toEndOf="@id/guidanceLayout"
69+
app:layout_constraintTop_toBottomOf="@id/scalebarLayout"
70+
tools:background="#eee"
71+
tools:layout_height="60dp"
72+
tools:layout_width="50dp" />
73+
74+
<FrameLayout
75+
android:id="@+id/emptyLeftContainer"
76+
android:layout_width="0dp"
77+
android:layout_height="0dp"
78+
android:layout_gravity="start|top"
79+
android:layout_marginStart="4dp"
80+
android:layout_marginTop="8dp"
81+
android:layout_marginBottom="8dp"
82+
app:layout_constraintBottom_toTopOf="@id/guidelineBottom"
83+
app:layout_constraintEnd_toStartOf="@id/guidelineBegin"
84+
app:layout_constraintStart_toStartOf="parent"
85+
app:layout_constraintTop_toBottomOf="@id/speedLimitLayout"
86+
tools:background="#F6A1A1" />
87+
88+
<FrameLayout
89+
android:id="@+id/emptyRightContainer"
90+
android:layout_width="wrap_content"
91+
android:layout_height="wrap_content"
92+
android:layout_gravity="start|top"
93+
android:layout_marginStart="4dp"
94+
android:layout_marginTop="8dp"
95+
android:layout_marginEnd="4dp"
96+
android:layout_marginBottom="8dp"
97+
app:layout_constraintBottom_toTopOf="@id/roadNameLayout"
98+
app:layout_constraintEnd_toEndOf="parent"
99+
app:layout_constraintTop_toBottomOf="@id/actionListLayout"
100+
tools:background="#F6A1A1"
101+
tools:layout_height="130dp"
102+
tools:layout_width="76dp" />
103+
104+
<FrameLayout
105+
android:id="@+id/actionListLayout"
106+
android:layout_width="@dimen/mapbox_actionList_width"
107+
android:layout_height="wrap_content"
108+
android:layout_marginTop="5dp"
109+
android:layout_marginEnd="8dp"
110+
android:gravity="top|right"
111+
app:layout_constraintEnd_toEndOf="parent"
112+
app:layout_constraintTop_toTopOf="parent"
113+
tools:background="#eee"
114+
tools:layout_height="200dp" />
115+
116+
<FrameLayout
117+
android:id="@+id/roadNameLayout"
118+
android:layout_width="wrap_content"
119+
android:layout_height="0dp"
120+
android:layout_gravity="center"
121+
android:layout_marginBottom="8dp"
122+
app:layout_constraintBottom_toBottomOf="parent"
123+
app:layout_constraintEnd_toEndOf="parent"
124+
app:layout_constraintHeight_max="62dp"
125+
app:layout_constraintStart_toStartOf="parent"
126+
tools:background="#eee"
127+
tools:layout_height="52dp"
128+
tools:layout_width="140dp" />
129+
130+
</androidx.constraintlayout.widget.ConstraintLayout>
141131

142132
<FrameLayout
143133
android:id="@+id/infoPanelLayout"

0 commit comments

Comments
 (0)