A composable that can be used to add extra actions to a composable (up to two) which will be revealed when the original composable is swiped to the left.
SwipeToRevealSample
@Composable
fun SwipeToRevealSample() {
val state = rememberRevealState()
val coroutineScope = rememberCoroutineScope()
SwipeToReveal(
state = state,
primaryAction = {
Box(
modifier =
Modifier.fillMaxSize().clickable {
/* Add the primary action */
coroutineScope.launch { state.animateTo(RevealValue.RightRevealed) }
},
contentAlignment = Alignment.Center,
) {
Icon(imageVector = Icons.Outlined.Delete, contentDescription = "Delete")
}
},
undoAction = {
Chip(
modifier = Modifier.fillMaxWidth(),
onClick = {
/* Add the undo action */
coroutineScope.launch { state.animateTo(RevealValue.Covered) }
},
colors = ChipDefaults.secondaryChipColors(),
label = { Text(text = "Undo") },
)
},
) {
Chip(
modifier =
Modifier.fillMaxWidth().semantics {
// Use custom actions to make the primary and secondary actions accessible
customActions =
listOf(
CustomAccessibilityAction("Delete") {
/* Add the primary action click handler */
true
}
)
},
onClick = { /* the click action associated with chip */ },
colors = ChipDefaults.secondaryChipColors(),
label = { Text(text = "Swipe Me") },
)
}
}
SwipeToRevealWithDelayedText
@Composable
fun SwipeToRevealWithDelayedText() {
val state = rememberRevealState()
val coroutineScope = rememberCoroutineScope()
SwipeToReveal(
state = state,
primaryAction = {
Row(
modifier =
Modifier.fillMaxSize().clickable {
/* Add the primary action */
coroutineScope.launch { state.animateTo(RevealValue.RightRevealed) }
},
horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically,
) {
Icon(imageVector = Icons.Outlined.Delete, contentDescription = "Delete")
if (abs(state.offset) > state.revealThreshold) {
// Delay the text appearance so that it has enough space to be displayed
val textAlpha =
animateFloatAsState(
targetValue = 1f,
animationSpec = tween(durationMillis = 250, delayMillis = 250),
label = "PrimaryActionTextAlpha",
)
Box(modifier = Modifier.graphicsLayer { alpha = textAlpha.value }) {
Spacer(Modifier.size(5.dp))
Text("Clear")
}
}
}
},
undoAction = {
Chip(
modifier = Modifier.fillMaxWidth(),
onClick = {
/* Add the undo action */
coroutineScope.launch { state.animateTo(RevealValue.Covered) }
},
colors = ChipDefaults.secondaryChipColors(),
label = { Text(text = "Undo") },
)
},
) {
Chip(
modifier =
Modifier.fillMaxWidth().semantics {
// Use custom actions to make the primary and secondary actions accessible
customActions =
listOf(
CustomAccessibilityAction("Delete") {
/* Add the primary action click handler */
true
}
)
},
onClick = { /* the click action associated with chip */ },
colors = ChipDefaults.secondaryChipColors(),
label = { Text(text = "Swipe Me") },
)
}
}
SwipeToRevealWithExpandables
/**
* A sample on how to use Swipe To Reveal within a list of items, preferably [ScalingLazyColumn].
*/
@Composable
fun SwipeToRevealWithExpandables() {
// Shape of actions should match with the overlay content. For example, Chips
// should use RoundedCornerShape(CornerSize(percent = 50)), Cards should use
// RoundedCornerShape with appropriate radius, based on the theme.
val actionShape = RoundedCornerShape(corner = CornerSize(percent = 50))
val itemCount = 10
val coroutineScope = rememberCoroutineScope()
val expandableStates = List(itemCount) { rememberExpandableState(initiallyExpanded = true) }
ScalingLazyColumn(modifier = Modifier.fillMaxSize()) {
item { ListHeader { Text("Scaling Lazy Column") } }
repeat(itemCount) { current ->
expandableItem(state = expandableStates[current]) { isExpanded ->
val revealState = rememberRevealState()
if (isExpanded) {
SwipeToReveal(
state = revealState,
primaryAction = {
Box(
modifier =
Modifier.fillMaxSize()
.background(Color.Red, actionShape)
.clickable {
coroutineScope.launch {
revealState.animateTo(RevealValue.RightRevealed)
}
},
contentAlignment = Alignment.Center,
) {
Icon(
imageVector = Icons.Outlined.Delete,
contentDescription = "Delete",
)
}
},
secondaryAction = {
Box(
modifier =
Modifier.fillMaxSize()
.background(Color.Gray, actionShape)
.clickable { /* trigger the optional action */ },
contentAlignment = Alignment.Center,
) {
Icon(
imageVector = Icons.Outlined.MoreVert,
contentDescription = "More Options",
)
}
},
undoAction = {
Chip(
modifier = Modifier.fillMaxWidth(),
onClick = {
coroutineScope.launch {
revealState.animateTo(RevealValue.Covered)
}
},
colors = ChipDefaults.secondaryChipColors(),
label = { Text(text = "Undo") },
)
},
onFullSwipe = {
coroutineScope.launch {
delay(1000)
expandableStates[current].expanded = false
}
},
) {
Chip(
modifier =
Modifier.fillMaxWidth().semantics {
// Use custom actions to make the primary and secondary actions
// accessible
customActions =
listOf(
CustomAccessibilityAction("Delete") {
/* Add the primary action click handler */
coroutineScope.launch {
revealState.animateTo(RevealValue.RightRevealed)
}
true
},
CustomAccessibilityAction("More Options") {
/* Add the secondary action click handler */
true
},
)
},
onClick = { /* the click action associated with chip */ },
colors = ChipDefaults.secondaryChipColors(),
label = { Text(text = "Swipe Me") },
)
}
}
}
}
}
}