I am trying to zoom images which are items inside my LazyColumn but when i try to zoom in it overlaps content with the other images and the scrolling of lazycolumn also becomes too difficult
var scale by remember { mutableStateOf(1f) }
var offset by remember { mutableStateOf(Offset(0f, 0f)) }
LazyColumn() {
items(mPdfRenderer?.pageCount!!) { message ->
Box(
modifier = Modifier
.fillMaxSize()
.pointerInput(Unit) {
detectTransformGestures { _, pan, zoom, _ ->
scale *= zoom
offset = Offset(
(offset.x + pan.x).coerceIn(
-200.dp.toPx(),
200.dp.toPx()
),
(offset.y + pan.y).coerceIn(
-200.dp.toPx(),
200.dp.toPx()
)
)
}
}
) {
Image(
bitmap = bitmap!!.asImageBitmap(),
contentDescription = "some useful description",
modifier = Modifier
.fillMaxWidth()
.border(width = 1.dp, color = Color.Gray)
.scale(scale)
.offset(offset.x.dp, offset.y.dp)
.aspectRatio(1f)
)
}
}
}
I am actually creating a pdf viewer. How can the zooming be improved so that content is not overlapped and the vertical scrolling remains smooth?
Check this to understand the zooming issue
The issue in your code is you are keeping single
var scale by remember { mutableStateOf(1f) }
var offset by remember { mutableStateOf(Offset(0f, 0f)) }
which applies to every item in LazyColumn while each pages should have its own scale and offset properties.
private class PdfProperties() {
var zoom = mutableStateOf(1f)
var offset = mutableStateOf(Offset.Zero)
}
or
val offsetMap = remember {
mutableStateMapOf<Int, Offset>()
}
val scaleMap = remember {
mutableStateMapOf<Int, Float>()
}
then you should apply and change offset and scale for each page.
This is how you should implement it with the Modifier which clips PDF page as in this ZoomableList.
https://stackoverflow.com/a/72668732/5457853
For smooth scrolling you should consume PointerInputChange
conditionally when number of fingers is bigger than 1 or zoom is bigger than 1f as in answer below.
https://stackoverflow.com/a/76021552/5457853
This custom gesture i wrote that is available in link above or as library here makes it easy to consume PointerInputChange conditionally as
Modifier.pointerInput(Unit) {
//zoom in/out and move around
detectTransformGestures(
pass = PointerEventPass.Initial,
onGesture = { gestureCentroid: Offset,
gesturePan: Offset,
gestureZoom: Float,
_,
_,
changes: List<PointerInputChange> ->
// 🔥Consume touch when multiple fingers down
// or zoom > 1f
// This prevents LazyColumn scrolling
val size = changes.size
if (size > 1) {
changes.forEach { it.consume() }
}
}
)
})
Also you can refer this answer too.
How to handle horizontal scroll gesture combined with transform gestures in Jetpack Compose
As i asked in comments if you want to limit zoom into Image
you should also call Modifier.clipToBounds if you wish to limit zoom inside Box also you might want to change zoom center and empty area by limiting pan in limits with
detectTransformGestures(
onGesture = { _, gesturePan, gestureZoom, _ ->
zoom = (zoom * gestureZoom).coerceIn(1f, 3f)
val newOffset = offset + gesturePan.times(zoom)
val maxX = (size.width * (zoom - 1) / 2f)
val maxY = (size.height * (zoom - 1) / 2f)
offset = Offset(
newOffset.x.coerceIn(-maxX, maxX),
newOffset.y.coerceIn(-maxY, maxY)
)
}
)
}
https://stackoverflow.com/a/72856350/5457853
And for natural pan and zooming which happens center of fingers instead of center of screen you can refer this official code
You can also consider checking this zoom library which offers features i mentioned above and more out of the box.