Android Jetpack Compose:如何在“框”中缩放图像?

时间:2021-02-02 07:08:54

标签: android android-jetpack-compose

我将在框内构建一个可缩放的图像视图,就像第一个屏幕截图一样。但是当我放大图像时,它会开箱即用。有没有办法缩放图像,但保持大小?如果没有 viewfragment,只有 box 似乎还不够。我期待图像变大,但仍然停留在红色框内,但放大后我得到了第二个屏幕截图。

Before zoom in After zoom in

多亏了 nglauber 和 Amirhosein,我得到了在“框”(固定区域)内同时具有缩放和拖动功能的最终解决方案,并将以下代码作为新的屏幕截图,如下所示。

        val imageBitmap = imageResource(id = R.drawable.android)
        Image(
            modifier = Modifier
                .preferredSize(400.dp, 300.dp)
                .clip(RectangleShape)
                .zoomable(onZoomDelta = { scale.value *= it })
                .rawDragGestureFilter(
                    object : DragObserver {
                        override fun onDrag(dragDistance: Offset): Offset {
                            translate.value = translate.value.plus(dragDistance)
                            return super.onDrag(dragDistance)
                        }
                    })
                .graphicsLayer(
                    scaleX = scale.value,
                    scaleY = scale.value,
                    translationX = translate.value.x,
                    translationY = translate.value.y
                ),
            contentDescription = null,
            bitmap = imageBitmap
        )

enter image description here

3 个答案:

答案 0 :(得分:3)

这是我的解决方案...可能对某人有帮助...

@Composable
fun ZoomableImage() {
    val scale = remember { mutableStateOf(1f) }
    val rotationState = remember { mutableStateOf(1f) }
    Box(
        modifier = Modifier
            .clip(RectangleShape) // Clip the box content
            .fillMaxSize() // Give the size you want...
            .background(Color.Gray)
            .pointerInput(Unit) {
                detectTransformGestures { centroid, pan, zoom, rotation ->
                    scale.value *= zoom
                    rotationState.value += rotation
                }
            }
    ) {
        Image(
            modifier = Modifier
                .align(Alignment.Center) // keep the image centralized into the Box
                .graphicsLayer(
                    // adding some zoom limits (min 50%, max 200%)
                    scaleX = maxOf(.5f, minOf(3f, scale.value)),
                    scaleY = maxOf(.5f, minOf(3f, scale.value)),
                    rotationZ = rotationState.value
                ),
            contentDescription = null,
            painter = painterResource(R.drawable.dog)
        )
    }
}

答案 1 :(得分:1)

只需将 zoomablerawDragGestureFilter 设置为 Image 而不是 Box

@Preview
@Composable
fun Zoomable(){
val scale = remember { mutableStateOf(1f) }
val translate = remember { mutableStateOf(Offset(0f, 0f)) }

Box(
    modifier = Modifier.preferredSize(300.dp)

) {
    val imageBitmap = imageResource(id = R.drawable.cover)
    Image(
        modifier = Modifier
            .zoomable(onZoomDelta = { scale.value *= it })
            .rawDragGestureFilter(
                object : DragObserver {
                    override fun onDrag(dragDistance: Offset): Offset {
                        translate.value = translate.value.plus(dragDistance)
                        return super.onDrag(dragDistance)
                    }
                })
            .graphicsLayer(
                scaleX = scale.value,
                scaleY = scale.value,
                translationX = translate.value.x,
                translationY = translate.value.y
            ),
        contentDescription = null,
        bitmap = imageBitmap
    )
  }
}

答案 2 :(得分:0)

zoomable 已弃用可以使用 PointerInputScope.detectTransformGestures

@Composable
fun ImagePreview(link: String) {
    Box(modifier = Modifier.fillMaxSize()) {
        var angle by remember { mutableStateOf(0f) }
        var zoom by remember { mutableStateOf(1f) }
        var offsetX by remember { mutableStateOf(0f) }
        var offsetY by remember { mutableStateOf(0f) }

        CoilImage(
            data = link,
            contentDescription = "image",
            contentScale = ContentScale.Fit,
            modifier = Modifier
                .offset { IntOffset(offsetX.roundToInt(), offsetY.roundToInt()) }
                .graphicsLayer(
                    scaleX = zoom,
                    scaleY = zoom,
                    rotationZ = angle
                )
                .pointerInput(Unit) {
                    detectTransformGestures(
                        onGesture = { _, pan, gestureZoom, gestureRotate ->
                            angle += gestureRotate
                            zoom *= gestureZoom
                            val x = pan.x * zoom
                            val y = pan.y * zoom
                            val angleRad = angle * PI / 180.0
                            offsetX += (x * cos(angleRad) - y * sin(angleRad)).toFloat()
                            offsetY += (x * sin(angleRad) + y * cos(angleRad)).toFloat()
                        }
                    )
                }
                .fillMaxSize()
        )
    }
}