i am using SwipeToDismiss (Material3) in order to swipe and dismiss items from a list. It works fine but i want to display a small animation for first time to the user in order to see that he is able to swipe and dismiss items from the list. Basically I want to display a small swipe (for example 20 dp) and then return to initial state.
In order to achieve the animation i did this:
@Composable
fun AnimatedItem(
onMeasuredHeight: (Dp) -> Unit = {}
) {
val animationDuration = 2000
val localDensity = LocalDensity.current
var height by remember {
mutableStateOf(0.dp)
}
var width by remember {
mutableStateOf(0.dp)
}
var isVisible by remember {
mutableStateOf(false)
}
Box(
modifier = Modifier
.background(
color = Color.White,
shape = RoundedCornerShape(8.dp)
)
.onGloballyPositioned { coordinates ->
height = with(localDensity) { coordinates.size.height.toDp() }
width = with(localDensity) { coordinates.size.width.toDp() }
onMeasuredHeight(height)
}
) {
AnimatedVisibility(
modifier = Modifier.align(Alignment.CenterEnd),
visible = isVisible,
enter = fadeIn(animationSpec = tween(durationMillis = animationDuration)) +
expandHorizontally(
expandFrom = Alignment.End,
animationSpec = tween(
durationMillis = animationDuration,
easing = FastOutSlowInEasing,
)
),
exit = fadeOut(
animationSpec = tween(
durationMillis = animationDuration,
easing = FastOutSlowInEasing,
)
) + shrinkHorizontally(
shrinkTowards = Alignment.End,
animationSpec = tween(
durationMillis = animationDuration,
easing = FastOutSlowInEasing,
)
)
) {
// the animated view
Box(
modifier = Modifier
.width(32.dp)
.height(height)
.background(
color = Color.Red,
shape = RoundedCornerShape(
topEnd = 8.dp,
bottomEnd = 8.dp
)
)
)
}
LaunchedEffect(Unit) {
delay(500)
isVisible = true
delay(1000)
isVisible = false
}
// the info view that does not pushed when red box enters
Column(
modifier = Modifier.padding(16.dp)
) {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
Text(
modifier = Modifier.padding(top = 8.dp),
text = "text 1",
style = MaterialTheme.typography.headlineMedium
)
Text(
modifier = Modifier.padding(top = 8.dp),
text = "text 2",
style = MaterialTheme.typography.headlineMedium
)
}
Text(
modifier = Modifier.padding(top = 8.dp),
text = "text 3",
style = MaterialTheme.typography.titleMedium
)
Text(
modifier = Modifier.padding(top = 2.dp),
text = "text 4",
style =MaterialTheme.typography.titleMedium,
)
}
}
}
As a result i can see the animation (a red view entering from end to start) but my question is : Is there a way to make it like the red view "push" the remaining view? Now it is like the red box is above the other one, and not pushing the existing one as entering the screen.
I tried to use a Row that contains the info view and the animated one (red box) but then the animation does not work at all.
Any help is welcome
I was approaching wrongly the solution.
Basically i added a red view on background and on top of that my actual row item view. So with the usage of offsetAnimation i have the required swipe animation (times can be adjusted based on our needs). My row item view swipes from end to start and the red background become visible. And then returns to initial state.
@Composable
fun AnimatedItem() {
val startDelay = 500L
val endDelay = 800L
var isVisible by remember {
mutableStateOf(false)
}
val targetValue: Dp = if (isVisible) {
20.dp
} else {
0.dp
}
val offsetAnimation: Dp by animateDpAsState(
targetValue = targetValue,
label = "",
animationSpec = tween(
durationMillis = 1000,
easing = FastOutSlowInEasing
)
)
Box(
modifier = Modifier
.background(
color = Color.Red,
shape = RoundedCornerShape(8.dp)
)
) {
Row(
modifier = Modifier
.fillMaxSize()
.offset(x = -offsetAnimation)
.background(
color = Color.White,
shape = RoundedCornerShape(8.dp)
)
) {
Column(
modifier = Modifier.padding(16.dp)
) {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
Text(
modifier = Modifier.padding(top = 8.dp),
text = "text 1",
style = MaterialTheme.typography.headlineMedium
)
Text(
modifier = Modifier.padding(top = 8.dp),
text = "text 2",
style = MaterialTheme.typography.headlineMedium
)
}
Text(
modifier = Modifier.padding(top = 8.dp),
text = "text 3",
style = MaterialTheme.typography.titleMedium
)
Text(
modifier = Modifier.padding(top = 2.dp),
text = "text 4",
style = MaterialTheme.typography.titleMedium,
)
}
LaunchedEffect(Unit) {
delay(startDelay)
isVisible = true
delay(endDelay)
isVisible = false
}
}
}
}