Zoomable Image with Jetpack Compose

My fella Android devs know that It’s a little bit of a pain to implement zoom-in — zoom-out for your ImageView
. It becomes more complicated when you want to be able to drag image on a screen at the same time. With traditional XML layout approach there are several ways of doing that. Generally, you would need to create an xml layout, override onTouchEvent
and use MothionEvents
to Translate (aka move) the image and use ScaleGestureDetector
to scale the image. Sometimes it creates a lot of boilerplate code and implementation becomes cumbersome.
In this article we are going to create Composable Image with support of zoom-in — zoom-out, drag on the screen option and load it asynchronously from URL. Also we will add maximum/minimum scale parameters to it.
With Jetpack Compose a lot of things have changed and now we don’t need to create xml layouts. Has complexity of operations with images changed? Let’s find out.
Jetpack Compose doesn’t support usage of ImageView
anymore and all views are replaced with Composable
functions. Now we have Image
which is an interface over NativeImage
.
Let’s start with the Composable function which shows the Image
with Drawable
resource:
In order to add zooming support to our image we will use zoomable
modifier and will pass there onZoomDelta
callback which is invoked when pinch/smooth zooming occurs. The callback receives the parameter — ratio of the new size compared to the old. It will be used to calculate thescale
state of the image.
The next step is to apply the scale to the Image
. graphicsLayer
modifier is responsible for this functionality. It can also be used to apply effects such as rotation, opacity, shadow, clipping and translation. The latter will be required in this implementation as well.
For the image dragging feature we will use therawDragGestureFilter
modifier. It detects dragging in any direction and with combination of DragObserver
/ Ondrag Event
we can get the offset which is the drag distance.
Most apps display images coming from remote servers so the next implementation step in this tutorial is to use Glide
to load the image asynchronously. Let’s also show Text
saying that “image is loading” until we get it from server for nicer user experience. On top of that, we are going to put our Image
and Text
into Column
which is similar to LinearLayout
and which allows to place its children in vertical sequence. Loading status will determine if Text
or Image
is shown.
Let’s also leverage the key wordremember
to persist the bitmap
variable as well as scale
and translation
.
And here is the complete code:
Now let’s see how we would use in a fragment:
To sum things up, in my opinion Jetpack Compose allowed to simplify zooming/dragging implementation for Image
. We were able to implement this plus async image loading and add some additional logic for minimum/maximum scale in around 50 lines of code. I liked the final result of fragment implementation where we can embed the composable function with just a few lines of code.