SwipeToDismissBox
Android
Component in Wear Material Compose
Wear Material [SwipeToDismissBox] that handles the swipe-to-dismiss gesture. Takes a single slot for the background (only displayed during the swipe gesture) and the foreground content.
Last updated:
Installation
dependencies {
implementation("androidx.wear.compose:compose-material:1.5.0-alpha04")
}
Overloads
@Composable
fun SwipeToDismissBox(
state: androidx.wear.compose.foundation.SwipeToDismissBoxState,
modifier: Modifier = Modifier,
backgroundScrimColor: Color = MaterialTheme.colors.background,
contentScrimColor: Color = MaterialTheme.colors.background,
backgroundKey: Any = SwipeToDismissKeys.Background,
contentKey: Any = SwipeToDismissKeys.Content,
hasBackground: Boolean = true,
content: @Composable BoxScope.(isBackground: Boolean) -> Unit
)
Parameters
name | description |
---|---|
state | State containing information about ongoing swipe or animation. |
modifier | Optional [Modifier] for this component. |
backgroundScrimColor | Color for background scrim |
contentScrimColor | Optional [Color] used for the scrim over the content composable during the swipe gesture. |
backgroundKey | Optional [key] which identifies the content currently composed in the [content] block when isBackground == true. Provide the backgroundKey if your background content will be displayed as a foreground after the swipe animation ends (as is common when [SwipeToDismissBox] is used for the navigation). This allows remembered state to be correctly moved between background and foreground. |
content | Slot for content, with the isBackground parameter enabling content to be displayed behind the foreground content - the background is normally hidden, is shown behind a scrim during the swipe gesture, and is shown without scrim once the finger passes the swipe-to-dismiss threshold. |
@Suppress("DEPRECATION")
@Deprecated(
"This overload is provided for backwards compatibility. " +
"A newer overload is available that uses " +
"androidx.wear.compose.foundation.SwipeToDismissBoxState.",
replaceWith =
ReplaceWith(
"SwipeToDismissBox(" +
"state, modifier, backgroundScrimColor, contentScrimColor, backgroundKey, contentKey," +
"hasBackground, content)"
)
)
@Composable
fun SwipeToDismissBox(
state: SwipeToDismissBoxState,
modifier: Modifier = Modifier,
backgroundScrimColor: Color = MaterialTheme.colors.background,
contentScrimColor: Color = MaterialTheme.colors.background,
backgroundKey: Any = SwipeToDismissKeys.Background,
contentKey: Any = SwipeToDismissKeys.Content,
hasBackground: Boolean = true,
content: @Composable BoxScope.(isBackground: Boolean) -> Unit
)
Parameters
name | description |
---|---|
state | State containing information about ongoing swipe or animation. |
modifier | Optional [Modifier] for this component. |
backgroundScrimColor | Color for background scrim |
contentScrimColor | Optional [Color] used for the scrim over the content composable during the swipe gesture. |
backgroundKey | Optional [key] which identifies the content currently composed in the [content] block when isBackground == true. Provide the backgroundKey if your background content will be displayed as a foreground after the swipe animation ends (as is common when [SwipeToDismissBox] is used for the navigation). This allows remembered state to be correctly moved between background and foreground. |
content | Slot for content, with the isBackground parameter enabling content to be displayed behind the foreground content - the background is normally hidden, is shown behind a scrim during the swipe gesture, and is shown without scrim once the finger passes the swipe-to-dismiss threshold. |
@Composable
fun SwipeToDismissBox(
onDismissed: () -> Unit,
modifier: Modifier = Modifier,
state: androidx.wear.compose.foundation.SwipeToDismissBoxState =
androidx.wear.compose.foundation.rememberSwipeToDismissBoxState(),
backgroundScrimColor: Color = MaterialTheme.colors.background,
contentScrimColor: Color = MaterialTheme.colors.background,
backgroundKey: Any = SwipeToDismissKeys.Background,
contentKey: Any = SwipeToDismissKeys.Content,
hasBackground: Boolean = true,
content: @Composable BoxScope.(isBackground: Boolean) -> Unit
)
Parameters
name | description |
---|---|
onDismissed | Executes when the swipe to dismiss has completed. |
modifier | Optional [Modifier] for this component. |
state | State containing information about ongoing swipe or animation. |
backgroundScrimColor | Color for background scrim |
contentScrimColor | Optional [Color] used for the scrim over the content composable during the swipe gesture. |
backgroundKey | Optional [key] which identifies the content currently composed in the [content] block when isBackground == true. Provide the backgroundKey if your background content will be displayed as a foreground after the swipe animation ends (as is common when [SwipeToDismissBox] is used for the navigation). This allows remembered state to be correctly moved between background and foreground. |
content | Slot for content, with the isBackground parameter enabling content to be displayed behind the foreground content - the background is normally hidden, is shown behind a scrim during the swipe gesture, and is shown without scrim once the finger passes the swipe-to-dismiss threshold. |
@Suppress("DEPRECATION")
@Deprecated(
"This overload is provided for backwards compatibility. " +
"A newer overload is available that uses " +
"androidx.wear.compose.foundation.SwipeToDismissBoxState.",
replaceWith =
ReplaceWith(
"SwipeToDismissBox(" +
"onDismiss, modifier, state, backgroundScrimColor, contentScrimColor, backgroundKey," +
"contentKey, hasBackground, content)"
),
level = DeprecationLevel.HIDDEN
)
@Composable
fun SwipeToDismissBox(
onDismissed: () -> Unit,
modifier: Modifier = Modifier,
state: SwipeToDismissBoxState = rememberSwipeToDismissBoxState(),
backgroundScrimColor: Color = MaterialTheme.colors.background,
contentScrimColor: Color = MaterialTheme.colors.background,
backgroundKey: Any = SwipeToDismissKeys.Background,
contentKey: Any = SwipeToDismissKeys.Content,
hasBackground: Boolean = true,
content: @Composable BoxScope.(isBackground: Boolean) -> Unit
)
Parameters
name | description |
---|---|
onDismissed | Executes when the swipe to dismiss has completed. |
modifier | Optional [Modifier] for this component. |
state | State containing information about ongoing swipe or animation. |
backgroundScrimColor | Color for background scrim |
contentScrimColor | Optional [Color] used for the scrim over the content composable during the swipe gesture. |
backgroundKey | Optional [key] which identifies the content currently composed in the [content] block when isBackground == true. Provide the backgroundKey if your background content will be displayed as a foreground after the swipe animation ends (as is common when [SwipeToDismissBox] is used for the navigation). This allows remembered state to be correctly moved between background and foreground. |
content | Slot for content, with the isBackground parameter enabling content to be displayed behind the foreground content - the background is normally hidden, is shown behind a scrim during the swipe gesture, and is shown without scrim once the finger passes the swipe-to-dismiss threshold. |
Code Examples
StatefulSwipeToDismissBox
@Composable
fun StatefulSwipeToDismissBox() {
// State for managing a 2-level navigation hierarchy between
// MainScreen and ItemScreen composables.
// Alternatively, use SwipeDismissableNavHost from wear.compose.navigation.
var showMainScreen by remember { mutableStateOf(true) }
val saveableStateHolder = rememberSaveableStateHolder()
// Swipe gesture dismisses ItemScreen to return to MainScreen.
val state = rememberSwipeToDismissBoxState()
LaunchedEffect(state.currentValue) {
if (state.currentValue == SwipeToDismissValue.Dismissed) {
state.snapTo(SwipeToDismissValue.Default)
showMainScreen = !showMainScreen
}
}
// Hierarchy is ListScreen -> ItemScreen, so we show ListScreen as the background behind
// the ItemScreen, otherwise there's no background to show.
SwipeToDismissBox(
state = state,
hasBackground = !showMainScreen,
backgroundKey = if (!showMainScreen) "MainKey" else "Background",
contentKey = if (showMainScreen) "MainKey" else "ItemKey",
) { isBackground ->
if (isBackground || showMainScreen) {
// Best practice would be to use State Hoisting and leave this composable stateless.
// Here, we want to support MainScreen being shown from different destinations
// (either in the foreground or in the background during swiping) - that can be achieved
// using SaveableStateHolder and rememberSaveable as shown below.
saveableStateHolder.SaveableStateProvider(
key = "MainKey",
content = {
// Composable that maintains its own state
// and can be shown in foreground or background.
val checked = rememberSaveable { mutableStateOf(true) }
Column(
modifier =
Modifier.fillMaxSize().padding(horizontal = 8.dp, vertical = 8.dp),
verticalArrangement =
Arrangement.spacedBy(4.dp, Alignment.CenterVertically),
) {
SplitToggleChip(
checked = checked.value,
label = { Text("Item details") },
modifier = Modifier.height(40.dp),
onCheckedChange = { v -> checked.value = v },
onClick = { showMainScreen = false },
toggleControl = {
Icon(
imageVector =
ToggleChipDefaults.checkboxIcon(checked = checked.value),
contentDescription = null,
)
}
)
}
}
)
} else {
Column(
modifier = Modifier.fillMaxSize().background(MaterialTheme.colors.primary),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center,
) {
Text("Show details here...", color = MaterialTheme.colors.onPrimary)
Text("Swipe right to dismiss", color = MaterialTheme.colors.onPrimary)
}
}
}
}
EdgeSwipeForSwipeToDismiss
@Composable
fun EdgeSwipeForSwipeToDismiss(navigateBack: () -> Unit) {
val state = rememberSwipeToDismissBoxState()
// When using Modifier.edgeSwipeToDismiss, it is required that the element on which the
// modifier applies exists within a SwipeToDismissBox which shares the same state.
SwipeToDismissBox(state = state, onDismissed = navigateBack) { isBackground ->
val horizontalScrollState = rememberScrollState(0)
if (isBackground) {
Box(modifier = Modifier.fillMaxSize().background(MaterialTheme.colors.secondaryVariant))
} else {
Box(modifier = Modifier.fillMaxSize()) {
Text(
modifier =
Modifier.align(Alignment.Center)
.edgeSwipeToDismiss(state)
.horizontalScroll(horizontalScrollState),
text =
"This text can be scrolled horizontally - to dismiss, swipe " +
"right from the left edge of the screen (called Edge Swiping)",
)
}
}
}
}
SimpleSwipeToDismissBox
@Composable
fun SimpleSwipeToDismissBox(navigateBack: () -> Unit) {
val state = rememberSwipeToDismissBoxState()
SwipeToDismissBox(state = state, onDismissed = navigateBack) { isBackground ->
if (isBackground) {
Box(modifier = Modifier.fillMaxSize().background(MaterialTheme.colors.secondaryVariant))
} else {
Column(
modifier = Modifier.fillMaxSize().background(MaterialTheme.colors.primary),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center,
) {
Text("Swipe right to dismiss", color = MaterialTheme.colors.onPrimary)
}
}
}
}