Deepak Gahlot
02/24/2021, 2:01 PM@ExperimentalFoundationApi
@ExperimentalAnimationApi
@Composable
fun ExpandableCard(
card: ItemsItem,
questions: List<ItemsItem>,
qResponse: Response
) {
val expanded = remember { mutableStateOf(false) }
val transitionState = remember {
MutableTransitionState(expanded.value).apply {
targetState = !expanded.value
}
}
val transition = updateTransition(transitionState)
val cardPaddingHorizontal by transition.animateDp({
tween(durationMillis = EXPAND_ANIMATION_DURATION)
}) {
if (expanded.value) 10.dp else 10.dp
}
val cardElevation by transition.animateDp({
tween(durationMillis = EXPAND_ANIMATION_DURATION)
}) {
if (expanded.value) 10.dp else 4.dp
}
val cardRoundedCorners by transition.animateDp({
tween(
durationMillis = EXPAND_ANIMATION_DURATION,
easing = FastOutSlowInEasing
)
}) {
if (expanded.value) 0.dp else 5.dp
}
val arrowRotationDegree by transition.animateFloat({
tween(durationMillis = EXPAND_ANIMATION_DURATION)
}) {
if (expanded.value) 0f else 180f
}
Card(
contentColor = colorResource(id = R.color.white),
elevation = cardElevation,
shape = RoundedCornerShape(cardRoundedCorners),
modifier = Modifier
.fillMaxWidth()
.padding(
horizontal = cardPaddingHorizontal,
vertical = 8.dp
)
) {
Column {
Row(
modifier = Modifier
.background(Color.White)
.padding(20.dp, 10.dp, 0.dp, 10.dp)
.fillMaxWidth()
.animateContentSize(),
horizontalArrangement = Arrangement.SpaceBetween
) {
@Suppress("DEPRECATION")
ConstraintLayout(
modifier = Modifier.fillMaxWidth()
) {
val (textField, iconImage) = createRefs()
Text(
text = card.qualifiedNumber + " " + card.label,
modifier = Modifier.constrainAs(textField) {
}
.padding(0.dp, 10.dp, 0.dp, 0.dp)
.fillMaxWidth(),
color = colorResource(id = R.color.black)
)
IconButton(
onClick = { if(expanded.value) { expanded.value = false } else { expanded.value = true } },
modifier = Modifier.constrainAs(iconImage) {
end.linkTo(parent.absoluteRight)
},
content = {
Icon(
painter = painterResource(id = R.drawable.ico_expand_arrow),
contentDescription = "Expandable Arrow",
modifier = Modifier.rotate(arrowRotationDegree),
tint = Color(R.color.black)
)
}
)
}
}
//Add the expandable content here
ExpandableContent(
questions as ArrayList<ItemsItem>,
qResponse, visible = expanded.value,
initialVisibility = expanded.value
)
}
}
}
this is the Code block i have written and the Card composable which is the parent is being executed for times, which i tap on the Icon for expanding the Layout.
It is working as expected , the logic for expand - collapse is working flawless, but since it is calling the child composable number of times, i'm processing a huge list of data that is also being called multiple times which is causing performance issues on the UI (edited)Doris Liu
02/25/2021, 6:54 AMTransition.animateFloat/animateDp
call, the if (expanded.value) 0f else 180f
is causing additional composition. In that lambda it's recommended to use the targetState that is passed to the lambda: if (it) 0f else 100f
so that external state change doesn't directly cause animations to recompose.Deepak Gahlot
02/25/2021, 7:14 AMDoris Liu
02/25/2021, 7:15 AMDeepak Gahlot
02/25/2021, 7:15 AMDoris Liu
02/25/2021, 7:18 AMTransition
, but targetState that is passed to the lambda. I.e. I'd change this
{
if (expanded.value) 0f else 180f
}
to
{it ->
if (it) 0f else 180f
}
targetState
than the actual one to query both the start and end values for seeking purposes. 🙂Deepak Gahlot
02/25/2021, 7:19 AMDoris Liu
02/25/2021, 7:32 AMDeepak Gahlot
02/25/2021, 7:48 AM