Last active
November 1, 2022 22:32
-
-
Save victorbrndls/8e83cc4d8ff35627693b5df09a9c1bc0 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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