user15686227
user15686227

Reputation:

How to have Image zoom in Jetpack compose?

Image zoom like of Instagram in jetpack compose if anyone can help

I want something like this https://drive.google.com/file/d/18a7SaPIoSObbvrmYxJ0GDhHXEETKpsEV/view?usp=drivesdk

Upvotes: 3

Views: 8303

Answers (2)

Mostafa Kashwaa
Mostafa Kashwaa

Reputation: 341

1- Save the scale as a state

var scale by remember { mutableStateOf(1f) }

2- Set the scale of your image to use this state. I recommend using graphicsLayer to set the scale in order to minimize the invalidated content, and add any other transformations you want like the following

Image(
        ...,
        modifier = Modifier
            .graphicsLayer(
                scaleX = scale,
                scaleY = scale
            )
    )

3- Use Modifier.pointerInput to detect and apply the zoom effect. with the PointerInputScope you can detect tabs and transformations namely (zoom, rotation and pan). For example you can add the following to detect zoom gestures and modify the scale accordingly.

modifier = Modifier
            .pointerInput(Unit) {
                detectTransformGestures { _, _, zoom, _ ->
                    scale = (scale * zoom).coerceIn(0.5f, 3f)
                }
            }

The other parameters of detectTransformGestures are centroid, pan and rotation. You don't need them for the zoom transformation but you will if you tried to apply rotation and translation.

If you want to apply the zoom using pan gesture you can use the detectTapGestures. Here is an example.

modifier = Modifier
            .pointerInput(Unit) {
                detectTapGestures(
                    onDoubleTap = {
                        scale = if (scale > 2f) 1f else 3f
                    }
                )
            }

Here is a complete sample using CoilImage. The implementation should be the same for any other Image

@Composable fun SamplePreview(imageUrl: String) {
var scale by remember { mutableStateOf(1f) }
Box {
    CoilImage(
        data = imageUrl,
        contentDescription = null,
        contentScale = ContentScale.FillWidth,
        modifier = Modifier
            .align(Alignment.Center)
            .graphicsLayer(
                scaleX = scale,
                scaleY = scale
            )
            .pointerInput(Unit) {
                detectTransformGestures { _, _, zoom, _ ->
                    scale = (scale * zoom).coerceIn(0.5f, 3f)
                }
            }
    ) {
        CircularProgressIndicator()
    }
}

Upvotes: 13

gnovakovski
gnovakovski

Reputation: 9

Did you make any progress? I am able to zoom the image, but I can't restore the image to the original size when user terminates the gesture. To zoom the image what I did was: Created a scale and state variables. The if(scale < 1) is to not let the user minimize the image.

var scale by remember { mutableStateOf(1f) }
val state = rememberTransformableState { zoomChange, _, _ ->
                scale *= zoomChange
                if(scale < 1){
                    scale = 1F
                }
        }

In the image, I used the graphicsLayer and the transformable.

.graphicsLayer{
                    scaleX = scale;
                    scaleY = scale
                }
.transformable(state = state)

I tried to capture the MotionEvent of the user, but didn't find a MotionEvent that observed the pinch gesture. Also, in the .pointerInput I can't use detectTapGestures and detectTransformGestures together, because the pointer just considers one.

Upvotes: 0

Related Questions