Skip to content

Instantly share code, notes, and snippets.

@victorbrndls
Last active November 1, 2022 22:32
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save victorbrndls/8e83cc4d8ff35627693b5df09a9c1bc0 to your computer and use it in GitHub Desktop.
Save victorbrndls/8e83cc4d8ff35627693b5df09a9c1bc0 to your computer and use it in GitHub Desktop.
LaunchedEffect(textLayoutInfoState.value) {
// textLayoutInfoState is only calculated if the text overflows
// its parent, if it doesn't, there's no need for the animation
val textLayoutInfo = textLayoutInfoState.value ?: return@LaunchedEffect
if (textLayoutInfo.textWidth <= textLayoutInfo.containerWidth) return@LaunchedEffect
// 7500 * 200 / 100 = 15s -- 2x container width
// 7500 * 500 / 250 = 15s -- 2x container width
// 7500 * 300 / 100 = 22.5s -- 3x container width
// 7500 * 110 / 100 = 8.25s -- 1.1x container width
// 7500 * 100 / 200 -- 1/2 container width, doesn't happen because of the if statement above
// the animation will always take at least 7.5s
val duration = 7500 * textLayoutInfo.textWidth / textLayoutInfo.containerWidth
// before the animation starts there's this delay, it's also taken
// into consideration between cycles
val delay = 1000L
do {
// simple animation that goes from 0 to negative text width,
// causes the text to scroll left because it's negative
val animation = TargetBasedAnimation(
animationSpec = infiniteRepeatable(
animation = tween(
durationMillis = duration,
delayMillis = 1000,
easing = LinearEasing
),
repeatMode = RepeatMode.Restart
),
typeConverter = Int.VectorConverter,
initialValue = 0,
targetValue = -textLayoutInfo.textWidth
)
// suspended function that is invoked when a new frame will be drawn
// returns the frame time in nanos
val startTime = withFrameNanos { it }
// this block will keep executing until the animation ends but given that
// the animation is `infiniteRepeatable` it never ends.
do {
// given that `withFrameNanos` is suspendable and runs only once
// per frame we don't need to worry about drawing too many times
val playTime = withFrameNanos { it } - startTime
offset = (animation.getValueFromNanos(playTime))
} while (!animation.isFinishedFromNanos(playTime))
// this code never runs
delay(delay)
} while (true)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment