Skip to content

Commit

Permalink
Sticky Behaviour feature for v2 BottomSheet (#573)
Browse files Browse the repository at this point in the history
* passing different threshold values for different drag direction

* improved boolean check

* swapped up and down varaibles action to correct, and added description of new params

* removed StickyBehavviour boolean param

* for null to and from case handled

* changed null checking and activity incoherence issues with threshold value update

---------

Co-authored-by: Anubhav Agrawal <[email protected]>
  • Loading branch information
Anubhvv and Anubhav Agrawal authored Dec 18, 2023
1 parent 0ba36ff commit fbb4b10
Show file tree
Hide file tree
Showing 2 changed files with 122 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,14 @@ import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.text.BasicText
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.Slider
import androidx.compose.material.SliderDefaults
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.ArrowBack
import androidx.compose.material.icons.outlined.ArrowForward
Expand All @@ -32,6 +35,7 @@ import androidx.compose.material.icons.outlined.Share
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableFloatStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
Expand Down Expand Up @@ -100,6 +104,9 @@ private fun CreateActivityUI() {

var peekHeightState by remember { mutableStateOf(110.dp) }

var stickyThresholdUpwardDrag: Float by remember { mutableStateOf(56f) }
var stickyThresholdDownwardDrag: Float by remember { mutableStateOf(56f) }

var hidden by remember { mutableStateOf(true) }

val bottomSheetState = rememberBottomSheetState(BottomSheetValue.Shown)
Expand Down Expand Up @@ -143,7 +150,9 @@ private fun CreateActivityUI() {
showHandle = showHandleState,
sheetState = bottomSheetState,
slideOver = slideOverState,
enableSwipeDismiss = enableSwipeDismiss
enableSwipeDismiss = enableSwipeDismiss,
stickyThresholdUpward = stickyThresholdUpwardDrag,
stickyThresholdDownward = stickyThresholdDownwardDrag
) {
Column(
verticalArrangement = Arrangement.spacedBy(10.dp),
Expand Down Expand Up @@ -291,6 +300,78 @@ private fun CreateActivityUI() {
onValueChange = { enableSwipeDismiss = it }
)
}
// New Row for Sticky Threshold Downward Drag
Row(
horizontalArrangement = Arrangement.spacedBy(30.dp),
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.fillMaxWidth()
) {
BasicText(
text = "Sticky Threshold Upward Drag",
modifier = Modifier.weight(1F),
style = TextStyle(
color = FluentTheme.aliasTokens.neutralForegroundColor[FluentAliasTokens.NeutralForegroundColorTokens.Foreground1].value(
themeMode = ThemeMode.Auto
)
)
)
Slider(
modifier = Modifier.width(100.dp).height(50.dp).padding(0.dp, 0.dp, 0.dp, 0.dp),
value = stickyThresholdUpwardDrag,
onValueChange = { stickyThresholdUpwardDrag = it
peekHeightState+=0.0001.dp
},
valueRange = 0f..500f,
colors = SliderDefaults.colors(
thumbColor = FluentTheme.aliasTokens.brandColor[FluentAliasTokens.BrandColorTokens.Color100],
activeTrackColor = FluentTheme.aliasTokens.brandColor[FluentAliasTokens.BrandColorTokens.Color10],
)
)
BasicText(
text = "%.1fdp".format(stickyThresholdUpwardDrag),
style = TextStyle(
color = FluentTheme.aliasTokens.neutralForegroundColor[FluentAliasTokens.NeutralForegroundColorTokens.Foreground1].value(
themeMode = ThemeMode.Auto
)
)
)
}
// New Row for Sticky Threshold Upward Drag
Row(
horizontalArrangement = Arrangement.spacedBy(30.dp),
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.fillMaxWidth()
) {
BasicText(
text = "Sticky Threshold Downward Drag",
modifier = Modifier.weight(1F),
style = TextStyle(
color = FluentTheme.aliasTokens.neutralForegroundColor[FluentAliasTokens.NeutralForegroundColorTokens.Foreground1].value(
themeMode = ThemeMode.Auto
)
)
)
Slider(
modifier = Modifier.width(100.dp).height(50.dp).padding(0.dp, 0.dp, 0.dp, 0.dp),
value = stickyThresholdDownwardDrag,
onValueChange = { stickyThresholdDownwardDrag = it
peekHeightState+=0.0001.dp
},
valueRange = 0f..500f,
colors = SliderDefaults.colors(
thumbColor = FluentTheme.aliasTokens.brandColor[FluentAliasTokens.BrandColorTokens.Color100],
activeTrackColor = FluentTheme.aliasTokens.brandColor[FluentAliasTokens.BrandColorTokens.Color10],
)
)
BasicText(
text = "%.1fdp".format(stickyThresholdDownwardDrag),
style = TextStyle(
color = FluentTheme.aliasTokens.neutralForegroundColor[FluentAliasTokens.NeutralForegroundColorTokens.Foreground1].value(
themeMode = ThemeMode.Auto
)
)
)
}
Row(
horizontalArrangement = Arrangement.spacedBy(16.dp),
verticalAlignment = Alignment.CenterVertically,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.dp
import com.microsoft.fluentui.compose.*
import com.microsoft.fluentui.compose.FixedThreshold
import com.microsoft.fluentui.compose.SwipeableDefaults
import com.microsoft.fluentui.compose.SwipeableState
import com.microsoft.fluentui.drawer.R
Expand Down Expand Up @@ -209,6 +210,8 @@ private const val BottomSheetOpenFraction = 0.5f
* @param slideOver if true, then sheetContent would be drawn in full length & it just get slided
* in the visible region. If false then, the sheetContainer placed at the bottom & its height could be at peekHeight, fullheight or hidden when dragged by Handle or swipe down.
* @param enableSwipeDismiss if false, bottomSheet will not be dismissed after swipe down gesture. Default value is false.
* @param stickyThresholdUpward The threshold for the upward drag gesture till which the sheet behaves sticky. Default value is 56f.
* @param stickyThresholdDownward The threshold for the downward drag gesture till which the sheet behaves sticky. Default value is 56f.y
* @param bottomSheetTokens tokens to provide appearance values. If not provided then bottomSheet
* tokens will be picked from [AppThemeController]
* @param content The content of rest of the screen.
Expand All @@ -225,6 +228,8 @@ fun BottomSheet(
showHandle: Boolean = true,
slideOver: Boolean = true,
enableSwipeDismiss: Boolean = false,
stickyThresholdUpward: Float = 56f,
stickyThresholdDownward: Float = 56f,
bottomSheetTokens: BottomSheetTokens? = null,
content: @Composable () -> Unit
) {
Expand Down Expand Up @@ -301,7 +306,10 @@ fun BottomSheet(
Modifier
.fillMaxWidth()
.nestedScroll(
if(!enableSwipeDismiss && sheetState.offset.value != null && sheetState.offset.value!! >= (fullHeight - dpToPx(peekHeight) ) )
if (!enableSwipeDismiss && sheetState.offset.value != null && sheetState.offset.value!! >= (fullHeight - dpToPx(
peekHeight
))
)
sheetState.NonDismissiblePostDownNestedScrollConnection
else if (slideOver) sheetState.PreUpPostDownNestedScrollConnection
else sheetState.PostDownNestedScrollConnection
Expand All @@ -319,6 +327,8 @@ fun BottomSheet(
.bottomSheetSwipeable(
sheetState,
expandable,
stickyThresholdDownward,
stickyThresholdUpward,
peekHeight,
fullHeight,
sheetHeightState.value,
Expand Down Expand Up @@ -349,7 +359,7 @@ fun BottomSheet(
.background(sheetBackgroundColor)
.semantics(mergeDescendants = true) {
if (sheetState.isVisible) {
if(enableSwipeDismiss) {
if (enableSwipeDismiss) {
dismiss {
if (sheetState.confirmStateChange(BottomSheetValue.Hidden)) {
scope.launch { sheetState.hide() }
Expand Down Expand Up @@ -386,21 +396,22 @@ fun BottomSheet(
.draggable(
orientation = Orientation.Vertical,
state = rememberDraggableState { delta ->
if(!enableSwipeDismiss && sheetState.offset.value != null && sheetState.offset.value!! >= (fullHeight - dpToPx(peekHeight) ) ){
if(delta<0){
if (!enableSwipeDismiss && sheetState.offset.value != null && sheetState.offset.value!! >= (fullHeight - dpToPx(
peekHeight
))
) {
if (delta < 0) {
sheetState.performDrag(delta)
}
}
else sheetState.performDrag(delta)
} else sheetState.performDrag(delta)
},
onDragStopped = { velocity ->
launch {
sheetState.performFling(velocity)
if (!sheetState.isVisible) {
if(enableSwipeDismiss) {
if (enableSwipeDismiss) {
scope.launch { sheetState.hide() }
}
else {
} else {
scope.launch { sheetState.show() }
}
}
Expand Down Expand Up @@ -456,6 +467,8 @@ fun BottomSheet(
private fun Modifier.bottomSheetSwipeable(
sheetState: BottomSheetState,
expandable: Boolean,
stickyThresholdDownward: Float,
stickyThresholdUpward: Float,
peekHeight: Dp,
fullHeight: Float,
sheetHeight: Float?,
Expand Down Expand Up @@ -495,8 +508,17 @@ private fun Modifier.bottomSheetSwipeable(
anchors = anchors,
orientation = Orientation.Vertical,
enabled = sheetState.currentValue != BottomSheetValue.Hidden,
thresholds = { from, to ->
val fromKey = anchors.entries.firstOrNull { it.value == from }?.key
val toKey = anchors.entries.firstOrNull { it.value == to }?.key

if(fromKey == null || toKey == null) { FixedThreshold(56.dp) } //in case of null defaulting to 56.dp threshold
else if (fromKey < toKey) { FixedThreshold(stickyThresholdDownward.dp) } // Threshold for drag down
else{ FixedThreshold(stickyThresholdUpward.dp) } // Threshold for drag up
},
resistance = null
)

} else {
Modifier
}
Expand All @@ -519,8 +541,17 @@ private fun Modifier.bottomSheetSwipeable(
anchors = anchors,
orientation = Orientation.Vertical,
enabled = sheetState.currentValue != BottomSheetValue.Hidden,
thresholds = { from, to ->
val fromKey = anchors.entries.firstOrNull { it.value == from }?.key
val toKey = anchors.entries.firstOrNull { it.value == to }?.key

if(fromKey == null || toKey == null) { FixedThreshold(56.dp) } //in case of null defaulting to 56 as a fallback
else if (fromKey < toKey) { FixedThreshold(stickyThresholdDownward.dp) } // Threshold for drag down
else{ FixedThreshold(stickyThresholdUpward.dp) } // Threshold for drag up
},
resistance = null
)

}

return this.then(modifier)
Expand Down

0 comments on commit fbb4b10

Please sign in to comment.