17
17
package com.materialstudies.reply.ui.nav
18
18
19
19
import android.view.View
20
+ import androidx.coordinatorlayout.widget.CoordinatorLayout
21
+ import androidx.core.view.doOnNextLayout
22
+ import com.google.android.material.R
20
23
import com.google.android.material.bottomsheet.BottomSheetBehavior
21
24
import com.materialstudies.reply.util.normalize
25
+ import kotlin.math.max
22
26
23
27
/* *
24
28
* A [BottomSheetBehavior.BottomSheetCallback] which helps break apart clients who would like to
@@ -30,17 +34,19 @@ import com.materialstudies.reply.util.normalize
30
34
* in [onSlide] is corrected to guarantee that the offset 0.0 <i>always</i> be exactly at the
31
35
* [BottomSheetBehavior.STATE_HALF_EXPANDED] state.
32
36
*/
33
- class BottomNavigationDrawerCallback : BottomSheetBehavior .BottomSheetCallback () {
37
+ class BottomNavigationDrawerCallback () : BottomSheetBehavior.BottomSheetCallback() {
34
38
35
39
private val onSlideActions: MutableList <OnSlideAction > = mutableListOf ()
36
40
private val onStateChangedActions: MutableList <OnStateChangedAction > = mutableListOf ()
37
41
38
42
private var lastSlideOffset = - 1.0F
39
- private var halfExpandedSlideOffset = 0.0F
43
+ private var halfExpandedSlideOffset = Float . MAX_VALUE
40
44
41
45
override fun onSlide (sheet : View , slideOffset : Float ) {
42
- lastSlideOffset = slideOffset
46
+ if (halfExpandedSlideOffset == Float .MAX_VALUE )
47
+ calculateInitialHalfExpandedSlideOffset(sheet)
43
48
49
+ lastSlideOffset = slideOffset
44
50
// Correct for the fact that the slideOffset is not zero when half expanded
45
51
val trueOffset = if (slideOffset <= halfExpandedSlideOffset) {
46
52
slideOffset.normalize(- 1F , halfExpandedSlideOffset, - 1F , 0F )
@@ -60,6 +66,37 @@ class BottomNavigationDrawerCallback : BottomSheetBehavior.BottomSheetCallback()
60
66
onStateChangedActions.forEach { it.onStateChanged(sheet, newState) }
61
67
}
62
68
69
+ /* *
70
+ * Calculate the onSlideOffset which will be given when the bottom sheet is in the
71
+ * [BottomSheetBehavior.STATE_HALF_EXPANDED] state.
72
+ *
73
+ * Recording the correct slide offset for the half expanded state happens in [onStateChanged].
74
+ * Since the first time the sheet is opened, we haven't yet received a call to [onStateChanged],
75
+ * this method is used to calculate the initial value manually so we can smoothly normalize
76
+ * slideOffset values received between -1 and 1.
77
+ *
78
+ * See:
79
+ * [BottomSheetBehavior.calculateCollapsedOffset]
80
+ * [BottomSheetBehavior.calculateHalfExpandedOffset]
81
+ * [BottomSheetBehavior.dispatchOnSlide]
82
+ */
83
+ private fun calculateInitialHalfExpandedSlideOffset (sheet : View ) {
84
+ val parent = sheet.parent as CoordinatorLayout
85
+ val behavior = BottomSheetBehavior .from(sheet)
86
+
87
+ val halfExpandedOffset = parent.height * (1 - behavior.halfExpandedRatio)
88
+ val peekHeightMin = parent.resources.getDimensionPixelSize(
89
+ R .dimen.design_bottom_sheet_peek_height_min
90
+ )
91
+ val peek = max(peekHeightMin, parent.height - parent.width * 9 / 16 )
92
+ val collapsedOffset = max(
93
+ parent.height - peek,
94
+ max(0 , parent.height - sheet.height)
95
+ )
96
+ halfExpandedSlideOffset =
97
+ (collapsedOffset - halfExpandedOffset) / (parent.height - collapsedOffset)
98
+ }
99
+
63
100
fun addOnSlideAction (action : OnSlideAction ): Boolean {
64
101
return onSlideActions.add(action)
65
102
}
0 commit comments