KotlinLeaner
03/07/2023, 2:27 PM@Preview(showBackground = true)
@Composable
fun MoveText() {
val density = LocalDensity.current
var columnHeightDp by remember {
mutableStateOf(0.dp)
}
var visible by remember { mutableStateOf(true) }
val iconOffsetAnimation: Dp by animateDpAsState(
if (visible) 13.dp else 0.dp, tween(1000)
)
val textOffsetAnimation: Dp by animateDpAsState(
if (visible) 6.dp else 0.dp, tween(1000)
)
val viewAlpha: Float by animateFloatAsState(
targetValue = if (visible) 1f else 0f, animationSpec = tween(
durationMillis = 1000,
)
)
val heightInDp: Dp by animateDpAsState(
targetValue = if (visible) {
columnHeightDp
} else {
0.dp
}, animationSpec = tween(
durationMillis = 1000,
)
)
ScrollComposeTheme {
Column(
modifier = Modifier
.fillMaxWidth()
.padding(start = 16.dp, top = 16.dp)
) {
Column(
modifier =
if (columnHeightDp != 0.dp) {
Modifier
.height(heightInDp)
} else {
Modifier
.onSizeChanged {
with(density) {
columnHeightDp = it.height.toDp()
}
}
.wrapContentHeight()
}
.background(Color.LightGray)
) {
Image(
modifier = Modifier.padding(top = iconOffsetAnimation),
alpha = viewAlpha,
imageVector = Icons.Default.ShoppingCart,
contentDescription = null,
)
Text(
modifier = Modifier.padding(top = textOffsetAnimation),
text = "Hello, Anna",
fontSize = 20.sp,
color = Color.Black.copy(alpha = viewAlpha),
)
}
Button(
modifier = Modifier.padding(top = 10.dp),
onClick = {
visible = !visible
},
) {
Text(text = "Move Text")
}
}
}
}
Zach Klippenstein (he/him) [MOD]
03/07/2023, 5:04 PMKotlinLeaner
03/09/2023, 8:50 PMcustom PaddingValues object that returns the animated values
? i didn't get it. Is there any example for this? I tried some piece of code to split into function
@Composable
private fun PaddingViewAnimation() {
var visible by remember { mutableStateOf(true) }
val iconOffsetAnimation: Dp by animateDpAsState(
if (visible) 13.dp else 0.dp, tween(1000)
)
PaddingViewAnimationStateLess(
{ iconOffsetAnimation },
visible,
onVisibleChange = {
visible = it
}
)
}
@Composable
fun PaddingViewAnimationStateLess(
iconOffsetAnimation: () -> Dp,
visible: Boolean,
onVisibleChange: (Boolean) -> Unit,
) {
Column(
modifier = Modifier
.fillMaxWidth()
.padding(start = 16.dp, top = 16.dp)
) {
Image(
modifier = Modifier.padding(top = iconOffsetAnimation()),
imageVector = Icons.Default.ShoppingCart,
contentDescription = null,
)
Button(
modifier = Modifier.padding(top = 10.dp),
onClick = {
onVisibleChange(!visible)
},
) {
Text(text = "Move Text")
}
}
}
Ben Trengrove [G]
03/09/2023, 9:17 PMModifier.padding()
runs in the composition phase so when you do Modifier.padding(top = iconOffsetAnimation())
you are reading state in composition and when it changes, you will get a recomposition. That deferred read with the lambda isn't actually helping you because of that.()
is running in composition. Any modifier that uses {}
is most likely running in one of the other phasesModifier.padding {}
for you to be able to call your lambda in. Probably the easiest way to optimise this if you were doing it just for learning would be to just build a custom layout using Modifier.layout {}
and make sure to read your animating state only in thereKotlinLeaner
03/09/2023, 9:22 PMModifer.layout
and try to learn.Zach Klippenstein (he/him) [MOD]
03/10/2023, 6:55 PMlayout
, much better for learning. For the record though, there’s a Modifier.padding()
overload that takes a PaddingValues
object. PaddingValues
is just an interface that has functions to calculate padding for left, top, right, and bottom. Those functions are read inside a layout
modifier. So you can create a class that implements that interface, and reads your animation state in each of those functions, and those state reads will happen inside, and only invalidate, the layout pass.
• padding modifier
• PaddingValues