ChapterNavigator use RollingNumber, no dynamic size

This commit is contained in:
Dude so hot committed 2026-10-08 03:57:28 +08:00
1 parent baf8333b70
commit 39398365e5
2 files changed
+74 -66

No files matched your search

@@ -6,7 +6,6 @@ import androidx.compose.foundation.interaction.collectIsDraggedAsState
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.CircleShape
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.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
@@ -20,6 +19,8 @@ import androidx.compose.ui.platform.LocalLayoutDirection
import androidx.compose.ui.unit.LayoutDirection import androidx.compose.ui.unit.LayoutDirection
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import com.ehviewer.core.ui.component.IntSliderState import com.ehviewer.core.ui.component.IntSliderState
import com.ehviewer.core.ui.component.RollingNumber
import com.ehviewer.core.ui.component.RollingNumberPlaceholder
import com.ehviewer.core.ui.component.Slider import com.ehviewer.core.ui.component.Slider
import com.ehviewer.core.ui.component.defaultMaxTickCount import com.ehviewer.core.ui.component.defaultMaxTickCount
import com.ehviewer.core.ui.util.HapticFeedbackType import com.ehviewer.core.ui.util.HapticFeedbackType
@@ -41,7 +42,7 @@ fun ChapterNavigator(
modifier = Modifier.padding(horizontal = horizontalPadding).clip(CircleShape).background(containerColor).padding(horizontal = 16.dp), modifier = Modifier.padding(horizontal = horizontalPadding).clip(CircleShape).background(containerColor).padding(horizontal = 16.dp),
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
) { ) {
Text(text = "${slider.value}") RollingNumber(slider.value, length = "$totalPages".length)
val maxTickCount = defaultMaxTickCount() val maxTickCount = defaultMaxTickCount()
val interactionSource = remember { MutableInteractionSource() } val interactionSource = remember { MutableInteractionSource() }
if (slider.state.steps < maxTickCount) { if (slider.state.steps < maxTickCount) {
@@ -60,6 +61,6 @@ fun ChapterNavigator(
maxTickCount = maxTickCount, maxTickCount = maxTickCount,
interactionSource = interactionSource, interactionSource = interactionSource,
) )
Text(text = "$totalPages") RollingNumberPlaceholder(totalPages)
} }
} }
@@ -13,6 +13,7 @@ import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.LocalTextStyle import androidx.compose.material3.LocalTextStyle
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
@@ -23,11 +24,13 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.takeOrElse import androidx.compose.ui.graphics.takeOrElse
import androidx.compose.ui.layout.layout import androidx.compose.ui.layout.layout
import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalLayoutDirection
import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.rememberTextMeasurer import androidx.compose.ui.text.rememberTextMeasurer
import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.DpSize import androidx.compose.ui.unit.DpSize
import androidx.compose.ui.unit.IntOffset import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.LayoutDirection
import androidx.compose.ui.unit.TextUnit import androidx.compose.ui.unit.TextUnit
import androidx.compose.ui.unit.toSize import androidx.compose.ui.unit.toSize
import kotlin.math.PI import kotlin.math.PI
@@ -55,14 +58,16 @@ fun rememberTextStyleNumberMaxSize(textStyle: TextStyle): DpSize {
fun RollingNumberPlaceholder(number: Int, style: TextStyle = LocalTextStyle.current) { fun RollingNumberPlaceholder(number: Int, style: TextStyle = LocalTextStyle.current) {
val styleNoSpacing = style.copy(letterSpacing = TextUnit.Unspecified) val styleNoSpacing = style.copy(letterSpacing = TextUnit.Unspecified)
val size = rememberTextStyleNumberMaxSize(style) val size = rememberTextStyleNumberMaxSize(style)
Row(horizontalArrangement = Arrangement.Center) { CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Ltr) {
"$number".forEach { char -> Row(horizontalArrangement = Arrangement.Center) {
Text( "$number".forEach { char ->
text = "$char", Text(
style = styleNoSpacing, text = "$char",
textAlign = TextAlign.Center, style = styleNoSpacing,
modifier = Modifier.size(size), textAlign = TextAlign.Center,
) modifier = Modifier.size(size),
)
}
} }
} }
} }
@@ -138,69 +143,71 @@ fun RollingNumber(
val transition = updateTransition(string) val transition = updateTransition(string)
val styleNoSpacing = style.merge(color = textColor).copy(letterSpacing = TextUnit.Unspecified) val styleNoSpacing = style.merge(color = textColor).copy(letterSpacing = TextUnit.Unspecified)
val size = rememberTextStyleNumberMaxSize(style) val size = rememberTextStyleNumberMaxSize(style)
LazyRow( CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Ltr) {
modifier = modifier.clipToBounds().layout { measurable, constraints -> LazyRow(
val placeable = measurable.measure(constraints.copy(maxHeight = Int.MAX_VALUE)) modifier = modifier.clipToBounds().layout { measurable, constraints ->
layout(width = placeable.width, height = size.height.roundToPx()) { val placeable = measurable.measure(constraints.copy(maxHeight = Int.MAX_VALUE))
placeable.place(0, 0) layout(width = placeable.width, height = size.height.roundToPx()) {
} placeable.place(0, 0)
}, }
reverseLayout = true, },
horizontalArrangement = Arrangement.Center, reverseLayout = true,
) { horizontalArrangement = Arrangement.Center,
val max = with(transition) { max(currentState.length, targetState.length) } ) {
items(max, key = { it }) { reversed -> val max = with(transition) { max(currentState.length, targetState.length) }
val rotate by transition.animateOffset { str -> items(max, key = { it }) { reversed ->
val len = str.length val rotate by transition.animateOffset { str ->
val absent = max - len val len = str.length
val where = max - reversed - 1 val absent = max - len
val v = if (where < absent) null else str[where - absent].digitToInt() val where = max - reversed - 1
conceptSpaceToIntermediate(v) val v = if (where < absent) null else str[where - absent].digitToInt()
} conceptSpaceToIntermediate(v)
if (reversed != 0 && reversed % 3 == 0 && separator) { }
Text( if (reversed != 0 && reversed % 3 == 0 && separator) {
text = ",",
modifier = Modifier.size(size),
style = styleNoSpacing,
textAlign = TextAlign.Center,
)
}
Column(
modifier = Modifier.animateItem().offset {
val number = intermediateToNumberOffset(rotate)
numberOffsetToUIOffset(size.height.roundToPx(), number)
},
horizontalAlignment = Alignment.CenterHorizontally,
) {
repeat(10) { i ->
Text( Text(
text = "$i", text = ",",
modifier = Modifier.size(size),
style = styleNoSpacing,
textAlign = TextAlign.Center,
)
Text(
text = "",
modifier = Modifier.size(size), modifier = Modifier.size(size),
style = styleNoSpacing, style = styleNoSpacing,
textAlign = TextAlign.Center, textAlign = TextAlign.Center,
) )
} }
Column(
modifier = Modifier.animateItem().offset {
val number = intermediateToNumberOffset(rotate)
numberOffsetToUIOffset(size.height.roundToPx(), number)
},
horizontalAlignment = Alignment.CenterHorizontally,
) {
repeat(10) { i ->
Text(
text = "$i",
modifier = Modifier.size(size),
style = styleNoSpacing,
textAlign = TextAlign.Center,
)
Text(
text = "",
modifier = Modifier.size(size),
style = styleNoSpacing,
textAlign = TextAlign.Center,
)
}
}
} }
} if (isNegative) {
if (isNegative) { item(key = -1) {
item(key = -1) { Text(
Text( text = "-",
text = "-", modifier = Modifier.size(size).animateItem(),
modifier = Modifier.size(size).animateItem(), style = styleNoSpacing,
style = styleNoSpacing, textAlign = TextAlign.Center,
textAlign = TextAlign.Center, )
) }
} }
} if (length != null) {
if (length != null) { items(length - max - if (isNegative) 1 else 0) {
items(length - max - if (isNegative) 1 else 0) { Spacer(Modifier.size(size))
Spacer(Modifier.size(size)) }
} }
} }
} }