将RIVE图形动画和文字动画分开处理。以下是几种可行的方案:

方案一:分层渲染(推荐)

1. RIVE端处理

· 在RIVE中只保留图形动画,移除所有文字图层

· 为文字区域创建占位图形或透明区域

· 导出不包含文字的.riv文件

2. Android端处理文字动画

```kotlin

class TextAnimationView @JvmOverloads constructor(

    context: Context,

    attrs: AttributeSet? = null

) : View(context, attrs) {

 

    private val textPaint = Paint().apply {

        isAntiAlias = true

        textSize = 16.spToPx()

        color = Color.WHITE

    }

    

    private var animatedText = ""

    private var textOffset = 0f

    private var textAlpha = 0f

 

    override fun onDraw(canvas: Canvas) {

        super.onDraw(canvas)

        

        // 自定义文字动画绘制

        textPaint.alpha = (textAlpha * 255).toInt()

        canvas.drawText(

            animatedText, 

            width / 2f + textOffset, 

            height / 2f, 

            textPaint

        )

    }

    // 文字动画方法

    fun animateText(text: String, duration: Long = 1000) {

        animatedText = text

        // 实现自定义动画逻辑

        val animator = ValueAnimator.ofFloat(0f, 1f).apply {

            this.duration = duration

            addUpdateListener { animation ->

                textAlpha = animation.animatedValue as Float

                textOffset = (animation.animatedValue as Float) * 100

                invalidate()

            }

        }

        animator.start()

    }

}

```

 

方案二:RIVE + Android文字层叠加

```kotlin

class SplitAnimationView @JvmOverloads constructor(

    context: Context,

    attrs: AttributeSet? = null

) : FrameLayout(context, attrs) {

 

    private val riveView: RiveAnimationView

    private val textContainer: FrameLayout

    

    init {

        // RIVE动画层

        riveView = RiveAnimationView(context).apply {

            setRiveResource(R.raw.graphics_animation_only)

            layoutParams = LayoutParams(MATCH_PARENT, MATCH_PARENT)

        }

        

        // 文字层

        textContainer = FrameLayout(context).apply {

            layoutParams = LayoutParams(MATCH_PARENT, MATCH_PARENT)

            setBackgroundColor(Color.TRANSPARENT)

        }

        

        addView(riveView)

        addView(textContainer)

    }

    

    fun setupTextAnimations(textConfigs: List<TextConfig>) {

        textConfigs.forEach { config ->

            val textView = TextView(context).apply {

                text = config.text

                setTextColor(config.color)

                textSize = config.size

                typeface = config.typeface

                // 设置位置

                x = config.x

                y = config.y

                alpha = 0f // 初始隐藏

            }

            

            textContainer.addView(textView)

            setupTextViewAnimation(textView, config)

        }

    }

    

    private fun setupTextViewAnimation(textView: TextView, config: TextConfig) {

        // 同步RIVE动画时间轴

        riveView.setOnFrameListener { frame ->

            // 根据RIVE动画进度控制文字动画

            val progress = frame.toFloat() / riveView.duration.toFloat()

            animateTextByProgress(textView, config, progress)

        }

    }

}

 

data class TextConfig(

    val text: String,

    val x: Float,

    val y: Float,

    val size: Float,

    val color: Int,

    val typeface: Typeface,

    val animationType: TextAnimationType

)

```

 

方案三:动态文字注入

```kotlin

class DynamicTextRiveView @JvmOverloads constructor(

    context: Context,

    attrs: AttributeSet? = null

) : RiveAnimationView(context, attrs) {

 

    private val textMap = mutableMapOf<String, String>()

    private val textArtboards = mutableMapOf<String, String>()

    

    fun registerTextSlot(artboardName: String, textNodeName: String, initialText: String) {

        val key = "$artboardName::$textNodeName"

        textMap[key] = initialText

        textArtboards[key] = artboardName

    }

    

    fun updateText(artboardName: String, textNodeName: String, newText: String) {

        val key = "$artboardName::$textNodeName"

        textMap[key] = newText

        refreshTextContent()

    }

    

    private fun refreshTextContent() {

        textMap.forEach { (key, text) ->

            val artboardName = textArtboards[key] ?: return@forEach

            // 这里需要根据RIVE SDK的具体API来动态更新文字

            // 伪代码:

            // getArtboard(artboardName)?.getTextNode(textNodeName)?.setText(text)

        }

        invalidate()

    }

}

```

 

方案四:使用RIVE的状态机控制文字

```kotlin

class StateControlledAnimationView : RiveAnimationView {

    

    fun setupTextAnimation() {

        // 使用RIVE状态机触发文字动画

        setOnStateChangeListener { stateName, _ ->

            when (stateName) {

                "show_text_1" -> showTextAnimation("动态文字1")

                "show_text_2" -> showTextAnimation("动态文字2")

                "hide_text" -> hideTextAnimation()

            }

        }

    }

    

    private fun showTextAnimation(text: String) {

        // Android端执行文字动画

        val textView = createAnimatedTextView(text)

        (parent as? ViewGroup)?.addView(textView)

        

        textView.animate()

            .alpha(1f)

            .translationY(0f)

            .setDuration(500)

            .start()

    }

}

```

 

多语言支持方案

```kotlin

class MultiLanguageAnimationHelper(

    private val riveView: RiveAnimationView,

    private val textContainer: ViewGroup

) {

    

    private val textResources = mapOf(

        "en" to mapOf(

            "welcome_text" to "Welcome",

            "button_text" to "Start"

        ),

        "zh" to mapOf(

            "welcome_text" to "欢迎",

            "button_text" to "开始"

        )

    )

    

    fun setLanguage(language: String) {

        val texts = textResources[language] ?: return

        

        // 更新所有文字元素

        updateAllTexts(texts)

        

        // 重新布局(如果需要)

        relayoutForLanguage(language)

    }

    

    private fun updateAllTexts(texts: Map<String, String>) {

        texts.forEach { (key, text) ->

            findTextViewByKey(key)?.text = text

        }

    }

}

```

 

优势总结

1. 灵活性:文字内容、字体、语言可动态调整

2. 维护性:图形和文字分离,便于单独修改

3. 性能:避免在RIVE中嵌入复杂文字动画

4. 本地化:多语言支持更加简单

5. 动态性:可根据运行时状态更新文字

 

建议从方案一开始尝试,它提供了最好的灵活性和维护性,同时保持了RIVE动画的质量。

 

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐