我正在尝试在 Jetpack Compose 中创建文本效果,其中文本使用画笔,看起来像是一组沿对角线平滑变化的颜色。文本中的各个字母应该上下移动,以及半圈。
我遇到了两个问题:
- 如果我尝试将画笔应用于整个单词,我不知道如何为移动和旋转的字母设置动画。这是我尝试过的代码:
Text(
text = word,
fontSize = fontSize,
style = LocalTextStyle.current.copy(brush = gradientBrush),
modifier = modifier
)
- 如果我将动画单独应用于每个字母,我可以通过动画实现所需的结果,但画笔也会单独应用于每个字母,从而产生不吸引人的效果。我需要将画笔应用于整个单词。这是我尝试过的代码:
Row {
word.forEachIndexed { index, char ->
val angle by rotationAngles[index]
val offset by letterOffsets[index]
Text(
text = char.toString(),
fontSize = fontSize,
style = LocalTextStyle.current.copy(brush = gradientBrush),
modifier = Modifier
.rotate(angle)
.offset(y = offset.dp)
)
}
}
这里有两个演示:
- 将画笔应用于整个单词的预期结果,但我不知道如何为字母设置动画。
- 应用动画的预期结果,但我无法将画笔应用于整个单词(画笔单独应用于每个字母)。
如何在 Jetpack Compose 中将画笔应用到整个单词时,为每个字母单独创建向上、向下和半转动的动画?
这是完整的代码:
@Preview(showBackground = true)
@Composable
fun RotatingLettersPreview() {
RotatingLetters("Medium")
}
@OptIn(ExperimentalTextApi::class)
@Composable
fun RotatingLetters(word: String,
fontSize: TextUnit = TextUnit.Unspecified,
modifier: Modifier = Modifier) {
val colorGradient = listOf(
Color(0xFFC0EFFF), // Light blue
Color(0xFF9BDBFB), // Medium blue
Color(0xFF75C2F9), // Dark blue
Color(0xFFF7D7C4), // Light pink
Color(0xFFF5B2C7), // Medium pink
Color(0xFFF28BAE), // Dark pink
Color(0xFFF7F2D4), // Light beige
Color(0xFFF5E0C3), // Medium beige
)
val fontSizeInPx = with(LocalDensity.current) { 30.sp.toPx() }
val doubleFontSizeInPx = fontSizeInPx * 2
val infiniteTransitionForOffset = rememberInfiniteTransition(label = "")
val offsetAnimation by infiniteTransitionForOffset.animateFloat(
initialValue = 0f,
targetValue = doubleFontSizeInPx,
animationSpec = infiniteRepeatable(tween(200000, easing = LinearEasing)), label = ""
)
val gradientBrush = remember(offsetAnimation) {
object : ShaderBrush() {
override fun createShader(size: Size): Shader {
val widthOffset = size.width * offsetAnimation
val heightOffset = size.height * offsetAnimation
return LinearGradientShader(
colors = colorGradient,
from = Offset(widthOffset, heightOffset),
to = Offset(widthOffset + size.width, heightOffset + size.height),
tileMode = TileMode.Mirror
)
}
}
}
val infiniteTransitionForRotation = rememberInfiniteTransition(label = "")
val rotationDirection = remember { mutableStateOf(1) }
val rotationAngles = List(word.length) { index ->
infiniteTransitionForRotation.animateFloat(
initialValue = 0f,
targetValue =
if (index % 2 == 0) 5f * rotationDirection.value else -5f * rotationDirection.value,
animationSpec = infiniteRepeatable(
animation = tween(250, easing = LinearEasing),
repeatMode = RepeatMode.Restart
), label = ""
)
}
LaunchedEffect(key1 = Unit) {
while (true) {
delay(250)
rotationDirection.value *= -1
}
}
val letterOffsets = List(word.length) { index ->
infiniteTransitionForRotation.animateFloat(
initialValue = 0f,
targetValue = if (index % 2 == 0) 2f else -2f,
animationSpec = infiniteRepeatable(
animation = tween(250, easing = LinearEasing),
repeatMode = RepeatMode.Reverse
), label = ""
)
}
Text(
text = word,
fontSize = fontSize,
style = LocalTextStyle.current.copy(brush = gradientBrush),
modifier = modifier
)
/*
Row {
word.forEachIndexed { index, char ->
val angle by rotationAngles[index]
val offset by letterOffsets[index]
Text(
text = char.toString(),
fontSize = fontSize,
style = LocalTextStyle.current.copy(brush = gradientBrush),
modifier = Modifier
.rotate(angle)
.offset(y = offset.dp)
)
}
}
*/
}
您可以通过使用drawWithContent和剪切每个字母的组合来实现类似的效果,以在所有字母上创建单个连续渐变。这是一个概念性的解决方案:
创建一个使用 Canvas 手动绘制文本的自定义可组合项,允许您在整个单词上应用单个渐变画笔。在绘制字符时,使用drawWithContent将绘图区域剪切到每个字符的边界,这样它们就可以独立地制作动画,同时仍然共享相同的画笔。以下是如何实现它的示例: