How to disable detectTransfromGestures() on horizontall scroll?

Viewed 23

I have the HorizontalPager with images. If the image has detectTransformGestures, the HorizontalPager will not scroll. If it's not there, then everything works. How can detectTransformGestures be disabled when scrolling horizontally.

        var size by remember { mutableStateOf(Size.Zero) }
        var scale by remember { mutableStateOf(1f) }
        var offset by remember { mutableStateOf(Offset.Zero) }

                HorizontalPager(
                    count = postPictures.size,
                    modifier = Modifier
                        .background(Color.Black.copy(alpha = 0.7f))
                        .fillMaxSize()
                        .onSizeChanged { size = it.toSize() }
                ) { image ->
                    GlideImage(
                        previewPlaceholder = 0,
                        imageOptions = ImageOptions(
                            contentScale = ContentScale.FillWidth
                        ),
                        requestOptions = { RequestOptions.skipMemoryCacheOf(false) },
                        modifier = Modifier
                            .clip(RoundedCornerShape(16.dp))
                            .pointerInput(Unit) {    
                                    detectTransformGestures(
                                        onGesture = { _, pan, zoom, _ ->
                                            val newScale: Float = (scale * zoom).coerceIn(1f, 4f)
                                            val newOffset = offset + pan
                                            scale = newScale

                                            val maxX = (size.width * (scale - 1) / 2f)
                                            val maxY = (size.height * (scale - 1) / 2f)

                                            offset = Offset(
                                                newOffset.x.coerceIn(-maxX, maxX),
                                                newOffset.y.coerceIn(-maxY, maxY)
                                            )
                                        }
                                    )
                                }
                            }
                            .graphicsLayer {
                                scaleX = scale
                                scaleY = scale
                                translationX = offset.x
                                translationY = offset.y
                            },
                        imageModel = postPictures[image],
                    )
1 Answers

You need to write you own detectTransformGestures that selectively calls PointerInputChange.consume to prevent scrolling. I wrote a library that extends default gestures that returns PointerInputChange that you can consume based on your preferences. It's here

Modifier.pointerInput(Unit) {
  detectTransformGestures(
    onGestureStart = {
    },
    onGesture = { gestureCentroid: Offset,
                  gesturePan: Offset,
                  gestureZoom: Float,
                  gestureRotate: Float,
                  mainPointerInputChange: PointerInputChange,
                  pointerList: List<PointerInputChange> ->
     
    },
    onGestureEnd = {
    
    }
  )
}

calling mainPointerInputChange.consume will prevent scrolling and you can call consume based on rotation, zoom or anything you prefer.

If you wish to have a zoom modifier that already does this with other options such as fling and moving back to bounds or limiting pan as in your code you can check out this library.

fun Modifier.enhancedZoom(
    key: Any? = Unit,
    clip: Boolean = true,
    enhancedZoomState: EnhancedZoomState,
    enabled: (Float, Offset, Float) -> Boolean = DefaultEnabled,
    zoomOnDoubleTap: (ZoomLevel) -> Float = enhancedZoomState.DefaultOnDoubleTap,
    onGestureStart: ((EnhancedZoomData) -> Unit)? = null,
    onGesture: ((EnhancedZoomData) -> Unit)? = null,
    onGestureEnd: ((EnhancedZoomData) -> Unit)? = null,
)

enabled lambda returns zoom, pan and rotation info to selectively enable or disable scrolling of other Composables.

Usage

Image(
    modifier = Modifier
        .background(Color.LightGray)
        .border(2.dp, Color.Red)
        .fillMaxWidth()
        .aspectRatio(4 / 3f)
        .enhancedZoom(
            clip = true,
            enhancedZoomState = rememberEnhancedZoomState(
                minZoom = .5f,
                imageSize = IntSize(width, height),
                limitPan = true,
                moveToBounds = true
            ),
            enabled = { zoom, pan, rotation ->
                (zoom > 1f)
            }
        ),
    bitmap = imageBitmap,
    contentDescription = "",
    contentScale = ContentScale.FillBounds
)
Related