2

I have a GlideImage that is inside a Box. Inside that Box, there is also a button with an icon. I want that, when I click on the button, the image is maximized and occupies the whole screen with a button in the lower right corner where it is possible to minimize it. I would also like to zoom in on it. Does anyone know how I can do this and if it's possible in the current state of Jetpack Compose?

I leave you the code I have to generate the Box, with the image and the icon.

Thanks in advance for any help.

@ExperimentalGlideComposeApi
@Composable
fun BuildImage(imageUrl: String) {
    Box(
        modifier = Modifier
            .padding(vertical = 25.dp, horizontal = 25.dp)
            .background(
                brush = Brush.linearGradient(
                    listOf(
                        Color.Gray,
                        Color.White
                    )
                ),
                shape = RoundedCornerShape(14.dp)
            )
            .clip(RoundedCornerShape(14.dp))
    ) {
        GlideImage(
            model = imageUrl,
            contentDescription = null,
            contentScale = ContentScale.FillBounds
        )

        Box(modifier = Modifier.matchParentSize(), contentAlignment = Alignment.BottomEnd) {
            IconButton(
                onClick = { /* TO IMPLEMENT */ },
                modifier = Modifier
                    .padding(11.dp)
                    .background(Color.Blue, RoundedCornerShape(3.dp))
                    .clip(RoundedCornerShape(3.dp))
                    .size(52.dp)
            ) {
                Icon(
                    painter = painterResource(id = R.drawable.maximize),
                    contentDescription = null,
                    tint = Color.Unspecified
                )
            }
        }
    }
}
R0ck
  • 409
  • 1
  • 15
  • Create a New Composable with fullscreen Image and Open it on maximize click . It can be a fullscreen dialog also .. To pinch zoom you can try something [like this](https://proandroiddev.com/zoomable-image-with-jetpack-compose-13b050675da5?gi=6dd4377f8998) or you can use any old xml library with `AndroidView` in compose. – ADM Nov 19 '22 at 16:05
  • @ADM I can't import zoomable extension from modifier, also can't import DragObserver. Am I missing something? – R0ck Nov 21 '22 at 14:12

2 Answers2

3

For my use case, I used the suggestion of @ADM to solve my problem. When I clicked on the button, a dialog opened that took up the entire screen and inside it showed the image I needed using Glide. To Zoom the image, I used the ZoomableImage method that you can see below.

Dialog(
    properties = DialogProperties(usePlatformDefaultWidth = false),
    onDismissRequest = { /* implement */ }
) {
    Box(modifier = Modifier.fillMaxSize()) {
      ZoomableImage(imageUrl)
    }
}

@ExperimentalGlideComposeApi
@Composable
fun ZoomableImage(model: Any, contentDescription: String? = null) {
    val angle by remember { mutableStateOf(0f) }
    var zoom by remember { mutableStateOf(1f) }
    var offsetX by remember { mutableStateOf(0f) }
    var offsetY by remember { mutableStateOf(0f) }

    val configuration = LocalConfiguration.current
    val screenWidth = configuration.screenWidthDp.dp.value
    val screenHeight = configuration.screenHeightDp.dp.value

    GlideImage(
        model,
        contentDescription = contentDescription,
        contentScale = ContentScale.Fit,
        modifier = Modifier
            .offset { IntOffset(offsetX.roundToInt(), offsetY.roundToInt()) }
            .graphicsLayer(
                scaleX = zoom,
                scaleY = zoom,
                rotationZ = angle
            )
            .pointerInput(Unit) {
                detectTransformGestures(
                    onGesture = { _, pan, gestureZoom, _ ->
                        zoom = (zoom * gestureZoom).coerceIn(1F..4F)
                        if (zoom > 1) {
                            val x = (pan.x * zoom)
                            val y = (pan.y * zoom)
                            val angleRad = angle * PI / 180.0

                            offsetX =
                                (offsetX + (x * cos(angleRad) - y * sin(angleRad)).toFloat()).coerceIn(
                                    -(screenWidth * zoom)..(screenWidth * zoom)
                                )
                            offsetY =
                                (offsetY + (x * sin(angleRad) + y * cos(angleRad)).toFloat()).coerceIn(
                                    -(screenHeight * zoom)..(screenHeight * zoom)
                                )
                        } else {
                            offsetX = 0F
                            offsetY = 0F
                        }
                    }
                )
            }
            .fillMaxSize()
    )
}
R0ck
  • 409
  • 1
  • 15
1

You can do it by following:

@OptIn(ExperimentalGlideComposeApi::class)
@Composable
fun Q74501531() {
    val configuration = LocalConfiguration.current
    val screenWidth = configuration.screenWidthDp.dp // Get screen width as dp from local configuration
    val screenHeight = configuration.screenHeight.dp // You can also get screen height but for demo it's unused

    Column(
        modifier = Modifier.fillMaxSize()
    ) {
        var isExpanded by remember { mutableStateOf(false) } // Trigger state for change width and height
        val width by animateDpAsState(if (isExpanded) screenWidth else screenWidth / 3)
        val height by animateDpAsState(if (isExpanded) screenWidth / 2 else screenWidth / 5)

        GlideImage(
            modifier = Modifier.size(width, height),
            model = "https://upload.wikimedia.org/wikipedia/commons/9/9a/Gull_portrait_ca_usa.jpg",
            contentDescription = null,
            contentScale = ContentScale.Crop
        )

        Spacer(Modifier.weight(1f))

        TextButton(
            modifier = Modifier
                .fillMaxWidth()
                .padding(horizontal = 8.dp),
            onClick = { isExpanded = !isExpanded }
        ) {
            Text("Toggle")
        }
    }
}

Demo: https://youtu.be/PwPagLi8nEs

Sky
  • 640
  • 5
  • 12