Stylianos Gakis
05/08/2023, 10:44 PMModifier.animateContentSize
to only work on one axis? Something like animatedContentHeight
would be what I am looking at, or a way to modify what animateContentSize
animates but can’t seem to find some API which does what I want.animateContentSize
and made it not animate the height 😅
Changed
val (width, height) = animateTo(measuredSize)
return layout(width, height) {
to
val (_, height) = animateTo(measuredSize)
return layout(measuredSize.width, height) {
And it just works 😛arty-parrot:
Here’s the entire thing
fun Modifier.animateContentHeight(
animationSpec: FiniteAnimationSpec<IntSize> = spring(),
finishedListener: ((initialValue: IntSize, targetValue: IntSize) -> Unit)? = null,
): Modifier = composed(
inspectorInfo = debugInspectorInfo {
name = "animateContentSize"
properties["animationSpec"] = animationSpec
properties["finishedListener"] = finishedListener
},
) {
val scope = rememberCoroutineScope()
val animModifier = remember(scope) {
HeightAnimationModifier(animationSpec, scope)
}
animModifier.listener = finishedListener
this.clipToBounds().then(animModifier)
}
private class HeightAnimationModifier(
val animSpec: AnimationSpec<IntSize>,
val scope: CoroutineScope,
) : LayoutModifierWithPassThroughIntrinsics() {
var listener: ((startSize: IntSize, endSize: IntSize) -> Unit)? = null
data class AnimData(
val anim: Animatable<IntSize, AnimationVector2D>,
var startSize: IntSize,
)
var animData: AnimData? by mutableStateOf(null)
override fun MeasureScope.measure(
measurable: Measurable,
constraints: Constraints,
): MeasureResult {
val placeable = measurable.measure(constraints)
val measuredSize = IntSize(placeable.width, placeable.height)
val (_, height) = animateTo(measuredSize)
return layout(measuredSize.width, height) {
placeable.placeRelative(0, 0)
}
}
fun animateTo(targetSize: IntSize): IntSize {
val data = animData?.apply {
if (targetSize != anim.targetValue) {
startSize = anim.value
scope.launch {
val result = anim.animateTo(targetSize, animSpec)
if (result.endReason == AnimationEndReason.Finished) {
listener?.invoke(startSize, result.endState.value)
}
}
}
} ?: AnimData(
Animatable(
targetSize,
IntSize.VectorConverter,
IntSize(1, 1),
),
targetSize,
)
animData = data
return data.anim.value
}
}
private abstract class LayoutModifierWithPassThroughIntrinsics : LayoutModifier {
final override fun IntrinsicMeasureScope.minIntrinsicWidth(
measurable: IntrinsicMeasurable,
height: Int,
) = measurable.minIntrinsicWidth(height)
final override fun IntrinsicMeasureScope.minIntrinsicHeight(
measurable: IntrinsicMeasurable,
width: Int,
) = measurable.minIntrinsicHeight(width)
final override fun IntrinsicMeasureScope.maxIntrinsicWidth(
measurable: IntrinsicMeasurable,
height: Int,
) = measurable.maxIntrinsicWidth(height)
final override fun IntrinsicMeasureScope.maxIntrinsicHeight(
measurable: IntrinsicMeasurable,
width: Int,
) = measurable.maxIntrinsicHeight(width)
}
Chris Fillmore
05/09/2023, 12:32 AMStylianos Gakis
05/09/2023, 8:55 AMBox(
Modifier
.layoutId(SupportingId)
.animateContentHeight()
.then(if (supporting == null) Modifier.requiredSize(0.dp) else Modifier)
.heightIn(min = MinSupportingTextLineHeight)
.wrapContentHeight()
.padding(HedvigTextFieldDefaults.supportingTextPadding()),
) {
if (supporting != null) {
supporting()
}
}