I have a Compose screen that needs to contain a long horizontal PNG image that initially shows as below, most of it showing off-screen to the right. I am needing to slowly animate it left, then right again (then repeat):

I was able to do this in old XML code and kotlin, but with Compose, I'm a bit lost on where to begin. As a first step (before even getting to the animating) - I attempted to use an Image for starters to show it off the screen by manually setting it a long size, but it squishes it within the view. I also tried this approach:
Canvas(
modifier = Modifier
.fillMaxSize()
) {
with(painter) {
draw(
size = Size(1000f, 300f),
)
}
}
But it still squishes the image within the view. I also tried
val imageBitmapSrc = ImageBitmap.imageResource(
LocalContext.current.resources,
R.drawable.landing_images2
)
Canvas(
modifier = Modifier
.fillMaxSize()
) {
drawImage(
image = imageBitmapSrc,
dstSize = IntSize(1000, 300)
)
}
Same result there as well, although at least with the last approach it lets me offset it off the screen (but the size is way off, should be very long and showing only part of the image without squishing it). Thoughts on what I'm doing wrong at least for this first step?
As a first step (before even getting to the animating) - I attempted to use an Image for starters to show it off the screen by manually setting it a long size, but it squishes it within the view.
You are on the right track, you just need to set appropriate content scale to the Image:
Image(
modifier = Modifier
.fillMaxWidth()
.height(300.dp),
painter = painterResource(R.drawable.landing_images2),
contentDescription = null,
contentScale = ContentScale.FillHeight,
)
This will create image with 300dp height and full width and it sets contentScale to ContentScale.FillHeight, which means that it will scale the image such that its height will be 300dp, preserving the aspect ratio of the original image. Default contentScale is ContentScale.Fit, which scales the image such that both dimensions fit the composable size - you don't want that and I guess this was your main problem.
The animation can then look like this:
val horizontalBias by rememberInfiniteTransition()
.animateFloat(
initialValue = -1F,
targetValue = 1F,
animationSpec = infiniteRepeatable(
animation = tween(3000),
repeatMode = RepeatMode.Reverse,
),
)
Image(
modifier = Modifier
.fillMaxWidth()
.height(300.dp),
painter = painterResource(R.drawable.landing_images2),
contentDescription = null,
contentScale = ContentScale.FillHeight,
alignment = BiasAlignment(horizontalBias, 0F),
)
This makes use of BiasAlignment, where BiasAlignment(-1F, 0F) aligns to center start and BiasAlignment(1F, 0F) aligns to center end. Simply animating horizontalBias from -1 to 1 infinitely then does the animation you want.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With