Skip to content

Instantly share code, notes, and snippets.

@cavin-macwan
Created February 20, 2025 18:16
Show Gist options
  • Save cavin-macwan/cdeeee5e71a25c340489b4a00e115311 to your computer and use it in GitHub Desktop.
Save cavin-macwan/cdeeee5e71a25c340489b4a00e115311 to your computer and use it in GitHub Desktop.
Expand & Collapse Animation for Accordion in Jetpack Compose
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