You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Wear OS Tile中使用Jetpack Compose实现跑马灯文本?

在Wear OS Tile中实现跑马灯文本

你的代码无效的核心原因是混淆了两个不同体系的API:Modifier.basicMarquee是Jetpack Compose UI库中的Modifier,无法直接应用在Wear Tile的ModifiersBuilders里——Tile的布局系统基于LayoutElement,不支持Compose UI的常规Modifier。

下面是两种可行的实现方案:

方案一:基础偏移动画实现跑马灯

通过Tile的AnimatedContent组件,结合X轴偏移动画实现文本滚动效果:

@ExperimentalWearTilesApi
private fun marqueeText(context: Context, text: String): LayoutElementBuilders.LayoutElement {
    // 定义从右到左的循环偏移动画
    val scrollAnimation = AnimationBuilders.RepeatableAnimation.Builder(
        AnimationBuilders.KeyframeAnimation.Builder<Float>()
            .setDurationMillis(7000) // 滚动一次的时长,可调整
            .addKeyframe(
                KeyframeElementBuilders.Keyframe.Builder<Float>()
                    .setFraction(0f)
                    .setValue(100f) // 起始偏移:容器宽度(100dp)
                    .build()
            )
            .addKeyframe(
                KeyframeElementBuilders.Keyframe.Builder<Float>()
                    .setFraction(1f)
                    .setValue(-200f) // 结束偏移:负的文本预估宽度,可根据实际调整
                    .build()
            )
            .build(),
        AnimationBuilders.RepeatMode.RESTART
    ).build()

    return LayoutElementBuilders.Box.Builder()
        .setWidth(DimensionBuilders.DpProp.Builder().setValue(100f).build())
        .setHeight(DimensionBuilders.WrapProp.Builder().build())
        .addContent(
            LayoutElementBuilders.AnimatedContent.Builder()
                .setAnimation(scrollAnimation)
                .setContent { progress ->
                    LayoutElementBuilders.Text.Builder(context, text)
                        .setTypography(Typography.TYPOGRAPHY_CAPTION2)
                        .setModifiers(
                            ModifiersBuilders.Modifiers.Builder()
                                .setOffset(
                                    ModifiersBuilders.OffsetModifier.Builder()
                                        .setX(DimensionBuilders.DpProp.Builder().setValue(progress).build())
                                        .build()
                                )
                                .build()
                        )
                        .build()
                }
                .build()
        )
        .build()
}

方案二:动态计算文本宽度的精准实现

通过TextMeasure获取文本实际宽度,仅当文本超出容器时才触发动画,避免无效滚动:

@ExperimentalWearTilesApi
private fun marqueeText(context: Context, text: String): LayoutElementBuilders.LayoutElement {
    val containerWidth = 100f
    val textStyle = Typography.TYPOGRAPHY_CAPTION2.resolve(context)
    // 计算文本实际宽度(转换为dp)
    val textWidth = TextMeasure.measureText(context, text, textStyle).width / context.resources.displayMetrics.density

    // 仅当文本宽度超过容器时创建动画
    val scrollAnimation = if (textWidth > containerWidth) {
        AnimationBuilders.RepeatableAnimation.Builder(
            AnimationBuilders.KeyframeAnimation.Builder<Float>()
                .setDurationMillis((textWidth * 60).toLong()) // 按文本长度动态设置时长,保持滚动速度一致
                .addKeyframe(
                    KeyframeElementBuilders.Keyframe.Builder<Float>()
                        .setFraction(0f)
                        .setValue(containerWidth)
                        .build()
                )
                .addKeyframe(
                    KeyframeElementBuilders.Keyframe.Builder<Float>()
                        .setFraction(1f)
                        .setValue(-textWidth)
                        .build()
                )
                .build(),
            AnimationBuilders.RepeatMode.RESTART
        ).build()
    } else {
        null
    }

    return LayoutElementBuilders.Box.Builder()
        .setWidth(DimensionBuilders.DpProp.Builder().setValue(containerWidth).build())
        .setHeight(DimensionBuilders.WrapProp.Builder().build())
        .addContent(
            scrollAnimation?.let { anim ->
                LayoutElementBuilders.AnimatedContent.Builder()
                    .setAnimation(anim)
                    .setContent { progress ->
                        LayoutElementBuilders.Text.Builder(context, text)
                            .setTypography(Typography.TYPOGRAPHY_CAPTION2)
                            .setModifiers(
                                ModifiersBuilders.Modifiers.Builder()
                                    .setOffset(
                                        ModifiersBuilders.OffsetModifier.Builder()
                                            .setX(DimensionBuilders.DpProp.Builder().setValue(progress).build())
                                            .build()
                                    )
                                    .build()
                            )
                            .build()
                    }
                    .build()
            } ?: LayoutElementBuilders.Text.Builder(context, text)
                .setTypography(Typography.TYPOGRAPHY_CAPTION2)
                .build()
        )
        .build()
}

注意事项

  • 需添加@ExperimentalWearTilesApi注解,因为AnimatedContent属于Wear Tile的实验性API
  • 可通过调整动画时长参数优化滚动速度,适配不同长度的文本
  • 方案二的动态计算能避免文本过短时的无效动画,提升用户体验

内容的提问来源于stack exchange,提问作者bourne86

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 01:40:23