How do I load url into Image into DrawImage in Compose UI Android Jetpack?
Asked Answered
A

14

40

I can use val image = +imageResource(R.drawable.header) and use DrawImage(image) to load image from Drawable Resource,

But how do I load a string url into the DrawImage(image)?. I've tried using Glide, but it needs to load into imageView. meanwhile DrawImage(image) doesn't take input from imageView.

Thanks.

Abecedarian answered 28/10, 2019 at 15:59 Comment(3)
I don't think this is supported yet. Do not forget that Compose is still in dev preview.Arch
You have to go old school and load the image yourself, take a look at: developer.android.com/reference/android/graphics/drawable/… :-)Cancellate
You can check out the gist: gist.github.com/anhvt52/bf9ee4a953f3421cbdbdd863650f10e8Ardenardency
J
25

Staring with 1.0.x the best way to achieve it is to use the Coil-Compose library.

Add in your build.gradle the dependency

dependencies {
    implementation("io.coil-kt:coil-compose:1.3.1")
}

Then just use:

Image(
    painter = rememberImagePainter("your url"),
    contentDescription = "My content description",
)

This loads the url passed in with rememberImagePainter, and then displays the resulting image using the standard Image composable.

Joellejoellen answered 18/3, 2021 at 8:23 Comment(2)
This does seem to be the case. The source code for com.google.accompanist.glide now contains "Accompanist-Glide is now deprecated. Consider using Coil: coil-kt.github.io/coil/compose"Pekingese
Wait, did I miss something or does Compose require a complete aditional library to just load an image from uri?Necromancy
T
13

Coil for Jetpack Compose

Another option to load an image from the internet.

Add the Coil dependency to build.gradle :

dependencies {
    implementation "io.coil-kt:coil-compose:1.4.0")
}

Simple use:

Image(
    painter = rememberImagePainter("https://picsum.photos/300/300"),
    contentDescription = stringResource(R.string.image_content_desc)
)

Don't forget to add the internet permission (AndroidManifest.xml)

<uses-permission android:name="android.permission.INTERNET"/>

More custom here: Jetpack Compose - Coil Document

Tartlet answered 5/5, 2021 at 10:12 Comment(0)
A
6

A solution loading a Bitmap from the url and using the asImageAsset() Bitmap extension method :

@Composable
fun loadPicture(url: String): UiState<Bitmap> {
    var bitmapState: UiState<Bitmap> by state<UiState<Bitmap>> { UiState.Loading }

    Glide.with(ContextAmbient.current)
        .asBitmap()
        .load(url)
        .into(object : CustomTarget<Bitmap>() {
            override fun onResourceReady(resource: Bitmap, transition: Transition<in Bitmap>?) {
                bitmapState = UiState.Success(resource)
            }

            override fun onLoadCleared(placeholder: Drawable?) { }
        })

    return bitmapState
}

Use the function with your Image() like this :

val loadPictureState = loadPicture(url)
if (loadPictureState is UiState.Success<Bitmap>)
    Image(loadPictureState.data.asImageAsset())
else
    Text("Loading...")

This snippet is using the Glide library and the UiState helper function from the JetNews official Google sample for Jetpack Compose

Aec answered 24/4, 2020 at 15:34 Comment(2)
This is outdated and can no longer be used.Dextrogyrate
(Also you might consider removing @Composable annotation from a non-composable function!)Agglomerate
M
3

You can use remember to watch a bitmap, then fetch it using Glide and update it as soon as you got it.

var bitmap by remember { mutableStateOf<Bitmap?>(null)}

Glide.with(ContextAmbient.current).asBitmap()
    .load("https://picsum.photos/200/300")
    .into(object : CustomTarget<Bitmap>() {
        override fun onResourceReady(resource: Bitmap, transition: Transition<in Bitmap>?) {
             bitmap = resource
          }

          override fun onLoadCleared(placeholder: Drawable?) {}
      })

You can then use it like this:


if (bitmap != null )
    Image(bitmap!!.asImageAsset(), Modifier.fillMaxWidth())
else
    Text("Loading Image...")

(This is a modern version of bviale's answer)

Medlock answered 30/10, 2020 at 16:21 Comment(1)
This will work, but image loading will be triggered for each re-composition. Although Glide has it's own local cache, we better wrap the Glide code with a LaunchedEffectRenvoi
C
3

add

dependencies {
    implementation "com.google.accompanist:accompanist-glide:0.10.0"
}

and then

    import androidx.compose.foundation.Image
    import com.google.accompanist.glide.rememberGlidePainter
    
    Image(
        painter = rememberGlidePainter("https://picsum.photos/300/300"),
        contentDescription = stringResource(R.string.image_content_desc),
        previewPlaceholder = R.drawable.placeholder,
    )

for now you can use "io.coil-kt:coil-compose:1.3.1"

Cerebrate answered 26/5, 2021 at 8:28 Comment(0)
A
3

For Compose 1.1.0 this snippet works like a charm, it shows the placeholder in Composable Preview:

@Composable
fun loadPicture(url: String, placeholder: Painter? = null): Painter? {

  var state by remember {
    mutableStateOf(placeholder)
  }

  val options: RequestOptions = RequestOptions().autoClone().diskCacheStrategy(DiskCacheStrategy.ALL)
  val context = LocalContext.current
  val result = object : CustomTarget<Bitmap>() {
    override fun onLoadCleared(p: Drawable?) {
      state = placeholder
    }

    override fun onResourceReady(
      resource: Bitmap,
      transition: Transition<in Bitmap>?,
    ) {
      state = BitmapPainter(resource.asImageBitmap())
    }
  }
  try {
    Glide.with(context)
      .asBitmap()
      .load(url)
      .apply(options)
      .into(result)
  } catch (e: Exception) {
    // Can't use LocalContext in Compose Preview
  }
  return state
}
@Composable
fun ImageItem() {
  val painter = loadPicture(
    url = item.image.fragments.image.href,
    placeholder = painterResource(id = R.drawable.tc_ic_no_image)
  )
  if (painter != null) {
    Image(painter = painter)
  }
}
Aloke answered 11/11, 2021 at 13:31 Comment(0)
Y
3

Add the Coil dependency to build.gradle :

dependencies {
      implementation "io.coil-kt:coil-compose:1.4.0")
}

Implementation in Code :

 Image(painter = rememberImagePainter(data = "https://image.tmdb.org/t/p/original/rr7E0NoGKxvbkb89eR1GwfoYjpA.jpg",
                                                builder = {
                                                    crossfade(true)
                                                    transformations(CircleCropTransformation())
                                                }),
                contentDescription = "Movie Poster")
Yellowhammer answered 11/3, 2022 at 11:30 Comment(1)
Just a small note that the rememberImagePainter has been deprecated. Android Studio will refactor it for you, but just in case it fails to do so, this is the new syntax: ``` painter = rememberAsyncImagePainter( ImageRequest.Builder(LocalContext.current) .data(data = "example.com/img.png") .apply(block = fun ImageRequest.Builder.() { crossfade(true) transformations(CircleCropTransformation()) }).build(), ) ```Unsophisticated
S
2

After Jetpack's beta release, using accompanist - Utils library for Jetpack Compose is the cleanest way for the above-mentioned use case.

Stunsail answered 3/3, 2021 at 8:41 Comment(1)
You linked to a third party fork, this is the official Google repo for Accompanist.Clyster
E
2

With the latest version of Coil - 2.1.0, rememberImagePainter() has been deprecated. AsyncImage has been introduced.

AsyncImage is a composable that that executes an image request asynchronously and renders the result. It supports the same arguments as the standard Image composable and additionally it supports setting placeholder/error/fallback painters and onLoading/onSuccess/onError callbacks.

Below is a simple example of how to use AsyncImage to load an image from a URL:

AsyncImage(
    model = "https://example.com/image.jpg",
    contentDescription = null
)

You can check the docs for more comprehensive explanation of AsyncImage

Emmerich answered 17/5, 2022 at 22:52 Comment(1)
https://example.com/image.jpg is a HTML page, so you won't see an image. Try to set another image URL.Cephalalgia
E
1

Try to use https://github.com/skydoves/landscapist

It seems to be realy good library to load images along with glide, coil, etc It enables to override handlers to do any custom things, e.q. when you got an error or during loading phase

Explicate answered 13/2, 2022 at 20:46 Comment(0)
V
0

Its support is still not added in Jetpack compose for some reason. But for the time being, you can use, this class

https://gist.github.com/nglauber/8a3c39db47813483d788fb2914f0f21f#file-image-kt

To use it, you need to invoke it this way :

Image(
  <your image url>,
  144.dp,
  96.dp
  )
}

You can check here to see how I used it. https://github.com/ranjeetsinha13/gobble/blob/f8d9bca4b010adf5b4aa59cc6e56f8612ee1de09/app/src/main/java/com/rs/gobble/ui/fragments/SearchFragment.kt#L120

Vespertine answered 8/1, 2020 at 10:0 Comment(0)
G
0

I have found a very easy way to show an image from an URL.

  1. Add dependencies{ implementation("io.coil-kt:coil:1.4.0") }

  2. Just do this

    imageView.load("https://www.example.com/image.jpg")

Also for a resource o file you can do this:

imageView.load(R.drawable.image)

imageView.load(File("/path/to/image.jpg"))

Requests can be configured with an optional trailing lambda:

imageView.load("https://www.example.com/image.jpg") {
    crossfade(true)
    placeholder(R.drawable.image)
    transformations(CircleCropTransformation())
}

I found this info from official coil page here: enter link description here

Gobetween answered 5/2, 2022 at 22:5 Comment(0)
A
0

Using Glide,

Follow Below Step

Add below dependancy in your app level gradle

def glide = "<Latest Version>"
implementation "com.github.bumptech.glide:glide:$glide"
annotationProcessor "com.github.bumptech.glide:compiler:$glide"

Create method like below in your ImageUtils class

@Composable
fun loadImage(url: String, @DrawableRes drawable: Int): MutableState<Bitmap?> {
    val bitmapState: MutableState<Bitmap?> = remember {
        mutableStateOf(null)
    }

    Glide.with(LocalContext.current)
        .asBitmap()
        .load(url)
        .into(object : CustomTarget<Bitmap>() {
            override fun onResourceReady(resource: Bitmap, transition: Transition<in Bitmap>?) {
                bitmapState.value = resource
            }

            override fun onLoadCleared(placeholder: Drawable?) {
            }

        })
    return bitmapState
}

Used like below wherever required in your app

model.imageUrl?.let { url ->
            val image = loadImage(url = url, drawable = DEFAUlT_IMAGE).value
            image?.let {
                Image(
                    modifier = Modifier
                        .fillMaxWidth()
                        .height(220.dp)
                        .padding(
                            top = 10.dp,
                            bottom = 10.dp,
                            start = 5.dp,
                            end = 5.dp
                        ),
                    bitmap = image.asImageBitmap(),
                    contentScale = ContentScale.Crop,
                    contentDescription = ""
                )
            }
        }

Here is an alternative approach that can also help you achieve this

  1. You may refer to the official Glide documentation for more information. Although this approach is simpler than the one mentioned earlier, it is still in an experimental state, and therefore, I have not recommended it.
  2. You can also used Accompanist for same

Other referance

Attalanta answered 22/3, 2023 at 8:33 Comment(0)
N
0

Solution

  • The easiest way to load an image in Jetpack Compose from a URL is to use AsyncImage from coil, like so:
@Composable
fun UrlImages(urlList:List<String>){

    LazyColumn(modifier = Modifier.padding(5.dp)){
        items(urlList){url ->
            AsyncImage(
                model = url,
                contentDescription = "pretty picture"
            )
            Spacer(modifier = Modifier.fillMaxWidth().height(10.dp))
        }
    }
    
}

The tricky part

  • The tricky part is trying to get all the proper aspect ratios, so the image looks normal and not compressed. For a 9/16 aspect ratio you could do this:
        val width = Resources.getSystem().displayMetrics.widthPixels
        val aspectHeight = (width * 0.5625).toInt()
  • Usually image URLs are defined as such where we can define the aspect ration inside of them:

https://static-cdn.fake.fakenet/fakeurl/imageendpoint-249x444.jpg

  • the 249x444 is the defined aspect ratio.
Nabob answered 17/7, 2023 at 21:33 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.