実践
@Composable
fun MarqueeText(
text: String,
speed: Float = 50f, // px/s
directionLeft: Boolean = true,
loop: Boolean = true,
textStyle: TextStyle = TextStyle.Default,
modifier: Modifier = Modifier
) {
val scrollState = rememberScrollState()
val coroutineScope = rememberCoroutineScope()
var textWidth by remember { mutableStateOf(0) }
var containerWidth by remember { mutableStateOf(0) }
LaunchedEffect(textWidth, containerWidth, speed, directionLeft) {
if (textWidth == 0 || containerWidth == 0) return@LaunchedEffect
val maxScroll = textWidth - containerWidth
if (maxScroll <= 0) return@LaunchedEffect
while (loop) {
val scrollRange = if (directionLeft) 0..maxScroll else maxScroll downTo 0
for (i in scrollRange) {
scrollState.scrollTo(i)
delay((1000 / speed).toLong())
}
}
}
Box(
modifier = modifier
.clipToBounds()
.onSizeChanged { containerWidth = it.width }
.horizontalScroll(scrollState, enabled = false)
) {
Text(
text = text,
style = textStyle,
modifier = Modifier
.onSizeChanged { textWidth = it.width }
)
}
}
MarqueeText(
text = "ながーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーいテキスト",
speed = 100f,
directionLeft = true,
loop = true,
textStyle = TextStyle(
fontSize = 20.sp,
color = Color.Black
),
modifier = Modifier
.fillMaxWidth()
.height(40.dp)
.background(Color.LightGray)
)
解説
scrollStateでスクルール方向を指定しています。
textWidth / containerWidthでテキストとコンテナのサイズ差分でスクロール可能範囲を決定
delay((1000 / speed)) スクロール速度の制御
loop = false にすれば 1 回だけスクロールさせることも可能
directionLeft = falseに変更することで逆方向へのスクロール
補足
scrollTo() の代わりに animateScrollTo() などを使用してもっと滑らかにアニメーションすることができるかも?