MangaSummary: Refactor to not use SubcomposeLayout (#10008)
This commit is contained in:
parent
c492efcb31
commit
0026f96fad
1 changed files with 55 additions and 54 deletions
|
@ -48,7 +48,6 @@ import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.CompositionLocalProvider
|
import androidx.compose.runtime.CompositionLocalProvider
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableIntStateOf
|
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.saveable.rememberSaveable
|
import androidx.compose.runtime.saveable.rememberSaveable
|
||||||
|
@ -63,9 +62,8 @@ import androidx.compose.ui.graphics.Brush
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.graphics.vector.ImageVector
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
import androidx.compose.ui.layout.ContentScale
|
import androidx.compose.ui.layout.ContentScale
|
||||||
import androidx.compose.ui.layout.SubcomposeLayout
|
import androidx.compose.ui.layout.Layout
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.platform.LocalDensity
|
|
||||||
import androidx.compose.ui.res.pluralStringResource
|
import androidx.compose.ui.res.pluralStringResource
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
|
@ -589,67 +587,70 @@ private fun MangaSummary(
|
||||||
expanded: Boolean,
|
expanded: Boolean,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
var expandedHeight by remember { mutableIntStateOf(0) }
|
|
||||||
var shrunkHeight by remember { mutableIntStateOf(0) }
|
|
||||||
val heightDelta = remember(expandedHeight, shrunkHeight) { expandedHeight - shrunkHeight }
|
|
||||||
val animProgress by animateFloatAsState(if (expanded) 1f else 0f)
|
val animProgress by animateFloatAsState(if (expanded) 1f else 0f)
|
||||||
val scrimHeight = with(LocalDensity.current) { remember { 24.sp.roundToPx() } }
|
Layout(
|
||||||
|
modifier = modifier.clipToBounds(),
|
||||||
SubcomposeLayout(modifier = modifier.clipToBounds()) { constraints ->
|
contents = listOf(
|
||||||
val shrunkPlaceable = subcompose("description-s") {
|
{
|
||||||
Text(
|
|
||||||
text = "\n\n", // Shows at least 3 lines
|
|
||||||
style = MaterialTheme.typography.bodyMedium,
|
|
||||||
)
|
|
||||||
}.map { it.measure(constraints) }
|
|
||||||
shrunkHeight = shrunkPlaceable.maxByOrNull { it.height }?.height ?: 0
|
|
||||||
|
|
||||||
val expandedPlaceable = subcompose("description-l") {
|
|
||||||
Text(
|
|
||||||
text = expandedDescription,
|
|
||||||
style = MaterialTheme.typography.bodyMedium,
|
|
||||||
)
|
|
||||||
}.map { it.measure(constraints) }
|
|
||||||
expandedHeight = expandedPlaceable.maxByOrNull { it.height }?.height?.coerceAtLeast(shrunkHeight) ?: 0
|
|
||||||
|
|
||||||
val actualPlaceable = subcompose("description") {
|
|
||||||
SelectionContainer {
|
|
||||||
Text(
|
Text(
|
||||||
text = if (expanded) expandedDescription else shrunkDescription,
|
text = "\n\n", // Shows at least 3 lines
|
||||||
maxLines = Int.MAX_VALUE,
|
|
||||||
style = MaterialTheme.typography.bodyMedium,
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
color = MaterialTheme.colorScheme.onBackground,
|
|
||||||
modifier = Modifier.secondaryItemAlpha(),
|
|
||||||
)
|
)
|
||||||
}
|
},
|
||||||
}.map { it.measure(constraints) }
|
{
|
||||||
|
Text(
|
||||||
|
text = expandedDescription,
|
||||||
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
SelectionContainer {
|
||||||
|
Text(
|
||||||
|
text = if (expanded) expandedDescription else shrunkDescription,
|
||||||
|
maxLines = Int.MAX_VALUE,
|
||||||
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
|
color = MaterialTheme.colorScheme.onBackground,
|
||||||
|
modifier = Modifier.secondaryItemAlpha(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
val colors = listOf(Color.Transparent, MaterialTheme.colorScheme.background)
|
||||||
|
Box(
|
||||||
|
modifier = Modifier.background(Brush.verticalGradient(colors = colors)),
|
||||||
|
contentAlignment = Alignment.Center,
|
||||||
|
) {
|
||||||
|
val image = AnimatedImageVector.animatedVectorResource(R.drawable.anim_caret_down)
|
||||||
|
Icon(
|
||||||
|
painter = rememberAnimatedVectorPainter(image, !expanded),
|
||||||
|
contentDescription = stringResource(if (expanded) R.string.manga_info_collapse else R.string.manga_info_expand),
|
||||||
|
tint = MaterialTheme.colorScheme.onBackground,
|
||||||
|
modifier = Modifier.background(Brush.radialGradient(colors = colors.asReversed())),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
) { (shrunk, expanded, actual, scrim), constraints ->
|
||||||
|
val shrunkHeight = shrunk.single()
|
||||||
|
.measure(constraints)
|
||||||
|
.height
|
||||||
|
val expandedHeight = expanded.single()
|
||||||
|
.measure(constraints)
|
||||||
|
.height
|
||||||
|
val heightDelta = expandedHeight - shrunkHeight
|
||||||
|
val scrimHeight = 24.dp.roundToPx()
|
||||||
|
|
||||||
val scrimPlaceable = subcompose("scrim") {
|
val actualPlaceable = actual.single()
|
||||||
val colors = listOf(Color.Transparent, MaterialTheme.colorScheme.background)
|
.measure(constraints)
|
||||||
Box(
|
val scrimPlaceable = scrim.single()
|
||||||
modifier = Modifier.background(Brush.verticalGradient(colors = colors)),
|
.measure(Constraints.fixed(width = constraints.maxWidth, height = scrimHeight))
|
||||||
contentAlignment = Alignment.Center,
|
|
||||||
) {
|
|
||||||
val image = AnimatedImageVector.animatedVectorResource(R.drawable.anim_caret_down)
|
|
||||||
Icon(
|
|
||||||
painter = rememberAnimatedVectorPainter(image, !expanded),
|
|
||||||
contentDescription = stringResource(if (expanded) R.string.manga_info_collapse else R.string.manga_info_expand),
|
|
||||||
tint = MaterialTheme.colorScheme.onBackground,
|
|
||||||
modifier = Modifier.background(Brush.radialGradient(colors = colors.asReversed())),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}.map { it.measure(Constraints.fixed(width = constraints.maxWidth, height = scrimHeight)) }
|
|
||||||
|
|
||||||
val currentHeight = shrunkHeight + ((heightDelta + scrimHeight) * animProgress).roundToInt()
|
val currentHeight = shrunkHeight + ((heightDelta + scrimHeight) * animProgress).roundToInt()
|
||||||
layout(constraints.maxWidth, currentHeight) {
|
layout(constraints.maxWidth, currentHeight) {
|
||||||
actualPlaceable.forEach {
|
actualPlaceable.place(0, 0)
|
||||||
it.place(0, 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
val scrimY = currentHeight - scrimHeight
|
val scrimY = currentHeight - scrimHeight
|
||||||
scrimPlaceable.forEach {
|
scrimPlaceable.place(0, scrimY)
|
||||||
it.place(0, scrimY)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Reference in a new issue