Files
coco 723ce1af5c a
2026-07-03 15:12:48 +08:00

3.9 KiB

Recipes

Modifier.zoomable()

Setting zoom limits

=== "Coil" ```kotlin hl_lines="2" val zoomableState = rememberZoomableState( zoomSpec = ZoomSpec(maxZoomFactor = 4f) )

ZoomableAsyncImage(
  state = rememberZoomableImageState(zoomableState),
  model = "https://example.com/image.jpg",
  contentDescription = …,
)
```

=== "Glide" ```kotlin hl_lines="2" val zoomableState = rememberZoomableState( zoomSpec = ZoomSpec(maxZoomFactor = 4f) )

ZoomableGlideImage(
  state = rememberZoomableImageState(zoomableState),
  model = "https://example.com/image.jpg",
  contentDescription = …,
)
```

Observing image loads

val imageState = rememberZoomableImageState()

// Whether the full quality image is loaded. This will be false for placeholders
// or thumbnails, in which case isPlaceholderDisplayed can be used instead.
val showLoadingIndicator = imageState.isImageDisplayed

AnimatedVisibility(visible = showLoadingIndicator) {
  CircularProgressIndicator()    
}

Grabbing downloaded images

Low resolution drawables can be accessed by using request listeners. These images are down-sampled by your image loading library to fit in memory and are suitable for simple use-cases such as color extraction.

=== "Coil" kotlin ZoomableAsyncImage( model = ImageRequest.Builder(LocalContext.current) .data("https://example.com/image.jpg") .listener(onSuccess = { _, result -> // TODO: do something with result.drawable. }) .build(), contentDescription = … ) === "Glide" kotlin ZoomableGlideImage( model = "https://example.com/image.jpg", contentDescription = … ) { it.addListener(object : RequestListener<Drawable> { override fun onResourceReady(resource: Drawable, …): Boolean { // TODO: do something with resource. } }) }

Full resolutions must be obtained as files because ZoomableImage streams them directly from disk. The easiest way to do this is to load them again from cache.

=== "Coil" ```kotlin val state = rememberZoomableImageState() ZoomableAsyncImage( model = imageUrl, state = state, contentDescription = …, )

if (state.isImageDisplayed) {
  Button(onClick = { downloadImage(context, imageUrl) }) {
    Text("Download image")
  }
}
```
```kotlin
suspend fun downloadImage(context: Context, imageUrl: HttpUrl) {
  val result = context.imageLoader.execute(
    ImageRequest.Builder(context)
      .data(imageUrl)
      .build()
  )
  if (result is SuccessResult) {
    val cacheKey = result.diskCacheKey ?: error("image wasn't saved to disk")
    val diskCache = context.imageLoader.diskCache!!
    diskCache.openSnapshot(cacheKey)!!.use { 
      // TODO: copy to Downloads directory.           
    }
  }
}
```

=== "Glide" ```kotlin val state = rememberZoomableImageState() ZoomableGlideImage( model = imageUrl, state = state, contentDescription = …, )

if (state.isImageDisplayed) {
  Button(onClick = { downloadImage(context, imageUrl) }) {
    Text("Download image")
  }
}
```
```kotlin
fun downloadImage(context: Context, imageUrl: Uri) {
  Glide.with(context)
    .download(imageUrl)
    .into(object : CustomTarget<File>() {
      override fun onResourceReady(resource: File, …) {
        // TODO: copy file to Downloads directory.
      }
      
      override fun onLoadCleared(placeholder: Drawable?) = Unit
    )
}
```