AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / coding / Perguntas / 77671536
Accepted
Oleksandr Myronchuk
Oleksandr Myronchuk
Asked: 2023-12-16 23:45:30 +0800 CST2023-12-16 23:45:30 +0800 CST 2023-12-16 23:45:30 +0800 CST

Aplicar efeito de pincel a uma palavra inteira enquanto anima cada letra individualmente no Jetpack Compose

  • 772

Estou tentando criar um efeito de texto no Jetpack Compose onde o texto usa um pincel que parece um conjunto de cores mudando suavemente na diagonal. As letras individuais do texto devem mover-se para cima e para baixo, bem como dar meias voltas.

Eu encontrei dois problemas:

  1. Se tento aplicar o pincel na palavra inteira, não sei como animar as letras que se movem e giram. Aqui está o código que tentei:
        Text(
        text = word,
        fontSize = fontSize,
        style = LocalTextStyle.current.copy(brush = gradientBrush),
        modifier = modifier
    )
  1. Se eu aplicar a animação em cada letra individualmente, consigo obter o resultado desejado com a animação, mas o pincel também é aplicado em cada letra individualmente, criando um efeito pouco atraente. Preciso que o pincel seja aplicado em toda a palavra. Aqui está o código que tentei:
    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)
            )
        }
    }

Aqui estão duas demonstrações:

insira a descrição da imagem aqui

  1. Resultado desejado de aplicar o pincel na palavra inteira, mas não sei animar as letras.
  2. Resultado desejado da aplicação da animação, mas não consigo aplicar o pincel na palavra inteira (o pincel é aplicado em cada letra individualmente).

Como posso criar uma animação de movimento para cima, para baixo e meio giro para cada letra individualmente, enquanto aplico o pincel à palavra inteira no Jetpack Compose?

Aqui está o código completo:

@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)
            )
        }
    }
*/
}
android-jetpack-compose
  • 1 1 respostas
  • 34 Views

1 respostas

  • Voted
  1. Best Answer
    Yazan
    2023-12-17T17:23:26+08:002023-12-17T17:23:26+08:00

    você pode obter um efeito semelhante usando uma combinação de drawWithContent e recortando cada letra para criar um único gradiente contínuo em todas as letras. Aqui está uma solução conceitual:

    Crie um elemento de composição personalizado que use o Canvas para desenhar o texto manualmente, permitindo aplicar um único pincel gradiente em toda a palavra. Use drawWithContent para recortar a área de desenho até os limites de cada caractere ao desenhá-los, para que cada um deles possa ser animado de forma independente enquanto ainda compartilham o mesmo pincel. Aqui está um exemplo de como você pode implementá-lo:

    @Composable
    fun AnimatedGradientText(word: String, gradientBrush: Brush, fontSize: TextUnit, modifier: Modifier = Modifier) {
        // Calculate text size, character positions, etc.
        val textPaint = remember {
            Paint().asFrameworkPaint().apply {
            isAntiAlias = true
            style = android.graphics.Paint.Style.FILL
        }
    }
    
    // For each letter, create a rotation and offset animation.
    val rotationAngles = remember { /* ... Your rotation animations ... */ }
    val letterOffsets = remember { /* ... Your offset animations ... */ }
    
    Canvas(modifier = modifier) {
        // Calculate text size and positions
        val textLayoutResult = remember(word, fontSize) { /* ... Measure text ... */ }
    
        word.forEachIndexed { index, char ->
            // Get animation values
            val angle: Float by rotationAngles[index]
            val offset: Float by letterOffsets[index]
    
            // Save the current canvas state
            save()
    
            // Position the canvas for this character
            translate(left + characterPositions[index], top)
    
            // Apply the rotation transformation
            rotate(angle)
    
            // Set the shader to the paint
            textPaint.shader = gradientBrush.asAndroidShader()
    
            // Draw this character
            drawContext.canvas.nativeCanvas.drawText(
                char.toString(),
                0f,
                0f + offset,
                textPaint
            )
    
            // Restore the canvas to avoid affecting subsequent characters
            restore()
        }
    }
    }
    
    • 1

relate perguntas

  • Problema com o Canvas no Jetpack Compose que não limpa o conteúdo desenhado ao definir StateFlow como nulo

  • Como fazer notas de piano no Jetpack Compose?

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    destaque o código em HTML usando <font color="#xxx">

    • 2 respostas
  • Marko Smith

    Por que a resolução de sobrecarga prefere std::nullptr_t a uma classe ao passar {}?

    • 1 respostas
  • Marko Smith

    Você pode usar uma lista de inicialização com chaves como argumento de modelo (padrão)?

    • 2 respostas
  • Marko Smith

    Por que as compreensões de lista criam uma função internamente?

    • 1 respostas
  • Marko Smith

    Estou tentando fazer o jogo pacman usando apenas o módulo Turtle Random e Math

    • 1 respostas
  • Marko Smith

    java.lang.NoSuchMethodError: 'void org.openqa.selenium.remote.http.ClientConfig.<init>(java.net.URI, java.time.Duration, java.time.Duratio

    • 3 respostas
  • Marko Smith

    Por que 'char -> int' é promoção, mas 'char -> short' é conversão (mas não promoção)?

    • 4 respostas
  • Marko Smith

    Por que o construtor de uma variável global não é chamado em uma biblioteca?

    • 1 respostas
  • Marko Smith

    Comportamento inconsistente de std::common_reference_with em tuplas. Qual é correto?

    • 1 respostas
  • Marko Smith

    Somente operações bit a bit para std::byte em C++ 17?

    • 1 respostas
  • Martin Hope
    fbrereto Por que a resolução de sobrecarga prefere std::nullptr_t a uma classe ao passar {}? 2023-12-21 00:31:04 +0800 CST
  • Martin Hope
    比尔盖子 Você pode usar uma lista de inicialização com chaves como argumento de modelo (padrão)? 2023-12-17 10:02:06 +0800 CST
  • Martin Hope
    Amir reza Riahi Por que as compreensões de lista criam uma função internamente? 2023-11-16 20:53:19 +0800 CST
  • Martin Hope
    Michael A formato fmt %H:%M:%S sem decimais 2023-11-11 01:13:05 +0800 CST
  • Martin Hope
    God I Hate Python std::views::filter do C++20 não filtrando a visualização corretamente 2023-08-27 18:40:35 +0800 CST
  • Martin Hope
    LiDa Cute Por que 'char -> int' é promoção, mas 'char -> short' é conversão (mas não promoção)? 2023-08-24 20:46:59 +0800 CST
  • Martin Hope
    jabaa Por que o construtor de uma variável global não é chamado em uma biblioteca? 2023-08-18 07:15:20 +0800 CST
  • Martin Hope
    Panagiotis Syskakis Comportamento inconsistente de std::common_reference_with em tuplas. Qual é correto? 2023-08-17 21:24:06 +0800 CST
  • Martin Hope
    Alex Guteniev Por que os compiladores perdem a vetorização aqui? 2023-08-17 18:58:07 +0800 CST
  • Martin Hope
    wimalopaan Somente operações bit a bit para std::byte em C++ 17? 2023-08-17 17:13:58 +0800 CST

Hot tag

python javascript c++ c# java typescript sql reactjs html

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve