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

Jetpack Compose:长横向图片屏幕外往复动画及显示问题

Compose长图往复滚动动画实现方案

先解决长图显示问题

你之前的错误在于没有给长图提供独立的布局空间,且未做裁剪处理:

  • 用Image组件时,若父布局是fillMaxSize(),Image的尺寸会被父布局约束压缩;
  • Canvas的绘制范围是其Modifier定义的fillMaxSize()(即屏幕大小),设置dstSize或size时,图片会被强制缩放到Canvas范围内,自然出现压缩。

正确的显示方式是用Box作为显示容器,固定容器高度,开启裁剪,让长图在容器内偏移,只显示容器范围内的部分:

Box(
    modifier = Modifier
        .fillMaxWidth()
        .height(300.dp) // 固定显示区域高度
        .clipToBounds() // 裁剪超出容器的图片部分
) {
    Image(
        painter = painterResource(id = R.drawable.landing_images2),
        contentDescription = "长横向图片",
        modifier = Modifier
            .size(width = 1000.dp, height = 300.dp) // 保持图片实际尺寸
            .offset(x = 200.dp) // 初始偏移,让大部分图片在屏幕右侧外
    )
}

实现往复滚动动画

用Compose的InfiniteTransition实现循环往复的左右移动动画,核心是计算需要偏移的总距离(图片宽度 - 屏幕宽度),然后设置循环动画:

val configuration = LocalConfiguration.current
val screenWidth = configuration.screenWidthDp.dp
val imageWidth = 1000.dp
// 计算需要偏移的最大距离:图片超出屏幕的部分
val maxOffset = screenWidth - imageWidth

val infiniteTransition = rememberInfiniteTransition()
val offsetX by infiniteTransition.animateFloat(
    initialValue = 0f, // 初始状态:图片左边缘对齐容器左边缘,右侧超出
    targetValue = maxOffset.value, // 目标状态:图片右边缘对齐容器右边缘,左侧超出
    animationSpec = infiniteRepeatable(
        animation = tween(durationMillis = 5000, easing = LinearEasing), // 5秒完成一次移动
        repeatMode = RepeatMode.Reverse // 到达目标后反向移动,实现往复
    )
)

Box(
    modifier = Modifier
        .fillMaxWidth()
        .height(300.dp)
        .clipToBounds()
) {
    Image(
        painter = painterResource(id = R.drawable.landing_images2),
        contentDescription = "长横向图片",
        modifier = Modifier
            .size(width = imageWidth, height = 300.dp)
            .offset(x = offsetX.dp)
    )
}

补充说明

如果需要保持图片原始比例,不要硬写固定高度,可通过painter.intrinsicSize获取图片宽高比,动态计算高度:

val painter = painterResource(id = R.drawable.landing_images2)
val imageRatio = painter.intrinsicSize.width / painter.intrinsicSize.height

Box(
    modifier = Modifier
        .fillMaxWidth()
        .aspectRatio(imageRatio) // 保持图片原始比例
        .clipToBounds()
) {
    Image(
        painter = painter,
        contentDescription = "长横向图片",
        modifier = Modifier
            .fillMaxHeight() // 按比例填充高度,宽度自然延伸
            .offset(x = offsetX.dp)
    )
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 08:12:39