“This is the 21st day of my participation in the First Challenge 2022. For details: First Challenge 2022”

Compose comes across a feature for browsing images that zooms in and out with two fingers

knowledge

Modifier.offset

The Modifier offset can offset the content. The offset can be positive or non-positive. Applying an offset only changes the position of the content and does not affect its size measurement.

Offset Indicates the offset that changes due to user interaction. It avoids recompilation when offsets change, and adds a graphical layer to prevent unnecessary redrawing of context when offsets change.

graphicsLayer

Draws content to elements in the draw layer. The drawing layer can be invalidated separately from the parent layer. When content is updated independently of anything above, graphicsLayer should be used to minimize invalid content.

GraphicsLayer can be used to apply various effects to content

  • Scaling (scaleX, scaleY)
  • Rotation (rotationX, rotationY, rotationZ)
  • Opacity (alpha)
  • Shadowed evation, Shape
  • Clip, Shape
  • And using Renderefect to change the result of the layer.

Officially, if you provide a non-zero shadow elevation and pass a concave shape, the shadow will not be drawn on Android versions less than 10.

An alpha value of less than 1.0f will implicitly crop its content to its boundaries. This is because an intermediate compositing layer is created to render the content into FIRST before drawing it to the target with the required alpha. The size of this layer is the same as the boundaries of the composable objects on which the modifier is configured, and anything outside these boundaries is ignored.

Modifier.pointerInput

Used to handle pointer input within the modified element area. Extension functions on PointerInputScope or AwaitPointerEventScope can be defined to perform higher levels of gesture detection. The pointer input processing block is cancelled and restarted when the pointer input is recombined with a different key 1.

PointerInputScope.detectTransformGestures

Gesture detector for rotation, panning, and zooming. OnGeture is called when any rotation, scaling, or translation occurs, passing the rotation Angle in degrees, amplifying the scale factor in pixels, and translating by offsets.

The logical explanation

Define four variables

var angle by remember { mutableStateOf(0f)}// The rotation Angle
var zoom by remember { mutableStateOf(1f)}/ / zoom
var offsetX by remember { mutableStateOf(0f)}// The X offset
var offsetY by remember { mutableStateOf(0f)}// The X offset
Copy the code

offset

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

Put it in graphicsLayer

.graphicsLayer(
    scaleX = zoom,
    scaleY = zoom,
    rotationZ = angle
)
Copy the code

Listening to the gestures

And then I’m going to listen for the gesture, get the value that the swipe returns and have the mutableStateOf tell graphicsLayer to refresh the UI

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

For an Image, just put an Image, and I’ll use the background color instead

 background(Color.Cyan)
Copy the code

The complete code

@Composable
private fun TransformGestures(a) {
    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()
    )
}
Copy the code

rendering