feat: add fade-in and shorten restart pause for ticker

Text now fades in over 300ms when it reappears instead of popping in.
Restart pause shortened from 1.5s to 0.5s. Initial 1.5s delay kept.
Switched from infiniteRepeatable to Animatable + LaunchedEffect loop
for independent control over initial vs subsequent cycles.

Made-with: Cursor
This commit is contained in:
cottongin
2026-03-18 04:10:23 -04:00
parent 9bd38224b1
commit 600687ab56

View File

@@ -5,13 +5,10 @@ import android.content.res.Configuration
import android.graphics.BitmapFactory
import androidx.compose.animation.AnimatedContent
import androidx.compose.animation.animateColorAsState
import androidx.compose.animation.core.Animatable
import androidx.compose.animation.core.LinearEasing
import androidx.compose.animation.core.RepeatMode
import androidx.compose.animation.core.animateFloat
import androidx.compose.animation.core.infiniteRepeatable
import androidx.compose.animation.core.keyframes
import androidx.compose.animation.core.rememberInfiniteTransition
import androidx.compose.animation.core.tween
import kotlinx.coroutines.delay
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.togetherWith
@@ -478,30 +475,36 @@ private fun TickerText(
val velocityPxPerMs = with(density) { velocityDpPerSecond.dp.toPx() } / 1000f
val totalScrollPx = textWidthPx + containerWidthPx
val scrollMs = (totalScrollPx / velocityPxPerMs).toInt()
val initialDelayMs = 1500
val durationMs = initialDelayMs + scrollMs
val transition = rememberInfiniteTransition(label = "ticker")
val offset by transition.animateFloat(
initialValue = 0f,
targetValue = 0f,
animationSpec = infiniteRepeatable(
animation = keyframes {
durationMillis = durationMs
0f at 0 using LinearEasing
0f at initialDelayMs using LinearEasing
-totalScrollPx at durationMs using LinearEasing
},
repeatMode = RepeatMode.Restart
),
label = "ticker"
)
val offset = remember { Animatable(0f) }
val alpha = remember { Animatable(0f) }
LaunchedEffect(textWidthPx, containerWidthPx) {
offset.snapTo(0f)
alpha.snapTo(0f)
alpha.animateTo(1f, tween(300))
delay(1500L)
while (true) {
offset.animateTo(
-totalScrollPx,
tween(scrollMs, easing = LinearEasing)
)
offset.snapTo(0f)
alpha.snapTo(0f)
alpha.animateTo(1f, tween(300))
delay(500L)
}
}
Box(
modifier = Modifier
.wrapContentWidth(align = Alignment.Start, unbounded = true)
.align(Alignment.CenterStart)
.graphicsLayer { translationX = offset }
.graphicsLayer {
translationX = offset.value
this.alpha = alpha.value
}
) {
if (strokeColor != null) {
Text(