Created
February 20, 2025 18:16
-
-
Save cavin-macwan/cdeeee5e71a25c340489b4a00e115311 to your computer and use it in GitHub Desktop.
Expand & Collapse Animation for Accordion in Jetpack Compose
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import android.os.Bundle | |
import androidx.activity.ComponentActivity | |
import androidx.activity.compose.setContent | |
import androidx.activity.enableEdgeToEdge | |
import androidx.compose.animation.AnimatedVisibility | |
import androidx.compose.animation.core.animateFloatAsState | |
import androidx.compose.animation.core.tween | |
import androidx.compose.animation.expandVertically | |
import androidx.compose.animation.fadeIn | |
import androidx.compose.animation.fadeOut | |
import androidx.compose.animation.shrinkVertically | |
import androidx.compose.foundation.background | |
import androidx.compose.foundation.clickable | |
import androidx.compose.foundation.layout.Arrangement | |
import androidx.compose.foundation.layout.Box | |
import androidx.compose.foundation.layout.Column | |
import androidx.compose.foundation.layout.Row | |
import androidx.compose.foundation.layout.fillMaxSize | |
import androidx.compose.foundation.layout.padding | |
import androidx.compose.foundation.shape.RoundedCornerShape | |
import androidx.compose.material.icons.Icons | |
import androidx.compose.material.icons.filled.ArrowDropDown | |
import androidx.compose.material.icons.filled.Face | |
import androidx.compose.material3.Icon | |
import androidx.compose.material3.MaterialTheme | |
import androidx.compose.material3.Surface | |
import androidx.compose.material3.Text | |
import androidx.compose.runtime.Composable | |
import androidx.compose.runtime.getValue | |
import androidx.compose.runtime.mutableStateOf | |
import androidx.compose.runtime.remember | |
import androidx.compose.runtime.setValue | |
import androidx.compose.ui.Alignment | |
import androidx.compose.ui.Modifier | |
import androidx.compose.ui.draw.clip | |
import androidx.compose.ui.draw.rotate | |
import androidx.compose.ui.text.font.FontWeight | |
import androidx.compose.ui.unit.dp | |
@Composable | |
fun Accordion(modifier: Modifier = Modifier) { | |
var expanded by remember { mutableStateOf(false) } | |
val arrowRotation by animateFloatAsState( | |
targetValue = if (expanded) 180f else 0f, | |
label = "accordion-arrow" | |
) | |
Surface( | |
color = MaterialTheme.colorScheme.surfaceDim, | |
modifier = modifier | |
// clip the ripple effect and background | |
.clip(RoundedCornerShape(12.dp)) | |
.clickable { expanded = !expanded } | |
) { | |
Column { | |
// accordion header | |
Row( | |
verticalAlignment = Alignment.CenterVertically, | |
horizontalArrangement = Arrangement.spacedBy(12.dp), | |
modifier = Modifier.padding(horizontal = 20.dp, vertical = 16.dp) | |
) { | |
Icon( | |
imageVector = Icons.Filled.Face, | |
contentDescription = null | |
) | |
Text( | |
text = "Click here to expand", | |
style = MaterialTheme.typography.bodyLarge, | |
fontWeight = FontWeight.Bold, | |
// make sure the text fill the row | |
modifier = Modifier.weight(1f) | |
) | |
Icon( | |
imageVector = Icons.Filled.ArrowDropDown, | |
contentDescription = null, | |
// arrow rotation based on the expanded state | |
modifier = Modifier.rotate(arrowRotation) | |
) | |
} | |
// accordion content | |
AnimatedVisibility( | |
visible = expanded, | |
// animate expand vertically from the top when expanded + fade in | |
enter = expandVertically( | |
expandFrom = Alignment.Top, | |
animationSpec = tween() | |
) + fadeIn(), | |
// animate shrink vertically to the top when collapsed + fade out | |
exit = shrinkVertically( | |
shrinkTowards = Alignment.Top, | |
animationSpec = tween() | |
) + fadeOut() | |
) { | |
// expandable item | |
Box( | |
modifier = Modifier | |
.padding(start = 8.dp, end = 8.dp, bottom = 8.dp) | |
.background( | |
color = MaterialTheme.colorScheme.surface, | |
shape = RoundedCornerShape(8.dp) | |
) | |
) { | |
Text( | |
text = "This is a bit long title so that you can get an idea how good this" + | |
"animation is", | |
style = MaterialTheme.typography.bodyMedium, | |
modifier = Modifier.padding(12.dp) | |
) | |
} | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment