Jetpack Compose 双指的拖拽

1,669 阅读3分钟

「这是我参与2022首次更文挑战的第21天,活动详情查看:2022首次更文挑战

Compose遇到一个浏览图片的功能,双指放大和缩小

知识点

Modifier.offset

Modifier的offset可以偏移内容。偏移量可以是正的,也可以是非正的。应用偏移只会更改内容的位置,而不会影响其大小测量。

offset由于用户交互而发生变化的偏移。它避免了在偏移量发生变化时进行重新编译,还添加了一个图形层,以防止在偏移量发生变化时对上下文进行不必要的重画。

graphicsLayer

使内容绘制到绘制层中的元素。绘图层可以与父层分开失效。当内容独立于上面的任何内容进行更新时,应使用graphicsLayer,以最小化无效内容。

graphicsLayer可以用于对内容应用各种效果

  • 缩放(scaleX、scaleY)
  • 旋转(rotationX、rotationY、rotationZ)
  • 不透明度(alpha)
  • 阴影(shadowElevation、shape)
  • 剪裁(clip、shape)
  • 以及使用Renderefect更改层的结果。

官方说,如果提供非零阴影高程,并且传递的形状为凹面,则阴影将不会在小于10的Android版本上绘制。

还有小于1.0f的alpha值会将其内容隐式剪裁到其边界。这是因为创建了一个中间合成层,以便在使用所需的alpha将内容绘制到目标之前,先将内容渲染到first中。该层的大小与配置该修改器的可组合对象的边界一致,这些边界之外的内容将被忽略。

Modifier.pointerInput

用于处理修改元素区域内的指针输入。 PointerInputScope或AwaitPointerEventScope上的扩展函数可以定义为执行更高级别的手势检测。指针输入处理块将被取消,并在指针输入用不同的键1重新组合时重新启动。

PointerInputScope.detectTransformGestures

可以用于旋转、平移和缩放的手势检测器。。当发生任何旋转、缩放或平移时,将调用OnGeture,以度为单位传递旋转角度,以像素为单位放大比例因子并以偏移量平移。

逻辑解释

定义4个变量

var angle by remember { mutableStateOf(0f) }//旋转的角度
var zoom by remember { mutableStateOf(1f) }//缩放
var offsetX by remember { mutableStateOf(0f) }//X轴偏移量
var offsetY by remember { mutableStateOf(0f) }//X轴偏移量

offset

Modifier
    .offset { IntOffset(offsetX.roundToInt(), offsetY.roundToInt()) }

传入graphicsLayer里面

.graphicsLayer(
    scaleX = zoom,
    scaleY = zoom,
    rotationZ = angle
)

监听手势

接着就是要监听手势,拿到手势的滑动返回的值让mutableStateOf告诉graphicsLayer刷新UI

.pointerInput(Unit) {
    detectTransformGestures(
        onGesture = { _, pan, gestureZoom, gestureRotate ->
            angle += gestureRotate
            zoom *= gestureZoom
            offsetX += pan.x
            offsetY += pan.y
        }
    )
}

图片的话加个Image就可以了,我在这里用背景色代替

 background(Color.Cyan)

完整代码

@Composable
private fun TransformGestures() {
    var angle by remember { mutableStateOf(0f) }
    var zoom by remember { mutableStateOf(1f) }
    var offsetX by remember { mutableStateOf(0f) }
    var offsetY by remember { mutableStateOf(0f) }
    Box(
        Modifier
            .offset { IntOffset(offsetX.roundToInt(), offsetY.roundToInt()) }
            .graphicsLayer(
                scaleX = zoom,
                scaleY = zoom,
                rotationZ = angle
            )
            .background(Color.Cyan)
            .pointerInput(Unit) {
                detectTransformGestures(
                    onGesture = { _, pan, gestureZoom, gestureRotate ->
                        angle += gestureRotate
                        zoom *= gestureZoom
                        offsetX += pan.x
                        offsetY += pan.y
                    }
                )
            }
            .fillMaxSize()
    )
}

效果图

ezgif.com-gif-maker (11).gif