38

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.

Adrian Hartanto
  • 509
  • 1
  • 5
  • 9
  • I don't think this is supported yet. Do not forget that Compose is still in dev preview. – Giorgos Neokleous Oct 28 '19 at 16:16
  • You have to go old school and load the image yourself, take a look at: https://developer.android.com/reference/android/graphics/drawable/Drawable#createFromStream(java.io.InputStream,%2520java.lang.String) :-) – Blundell Oct 30 '19 at 14:03
  • You can check out the gist: https://gist.github.com/anhvt52/bf9ee4a953f3421cbdbdd863650f10e8 – Anh Vu Jan 21 '21 at 07:52

14 Answers14

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.

Gabriele Mariotti
  • 320,139
  • 94
  • 887
  • 841
  • 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: https://coil-kt.github.io/coil/compose" – Alt-Cat Aug 18 '21 at 14:52
  • 2
    Wait, did I miss something or does Compose require a complete aditional library to just load an image from uri? – Chapz Nov 06 '21 at 17:31
12

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

Wilson Tran
  • 4,050
  • 3
  • 22
  • 31
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

bviale
  • 5,245
  • 3
  • 28
  • 48
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)

thedjdoorn
  • 41
  • 6
  • 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 `LaunchedEffect` – TareK Khoury May 09 '22 at 16:09
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"

EunhaEonnie
  • 223
  • 2
  • 4
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)
  }
}
Martin K
  • 782
  • 7
  • 13
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")
Alok Gupta
  • 1,806
  • 22
  • 21
  • 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 = "https://example.com/img.png") .apply(block = fun ImageRequest.Builder.() { crossfade(true) transformations(CircleCropTransformation()) }).build(), ) ``` – netcyrax Apr 04 '23 at 06:39
2

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

araut
  • 576
  • 4
  • 11
  • You linked to a third party fork, [this](https://github.com/google/accompanist) is the official Google repo for Accompanist. – Jorn Aug 15 '23 at 06:44
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

Francis S
  • 138
  • 1
  • 7
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

EzYy
  • 91
  • 1
  • 4
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

Ranjeet
  • 393
  • 2
  • 10
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

Daniel S.
  • 2,629
  • 2
  • 21
  • 19
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

Chirag Solanki
  • 1,107
  • 2
  • 13
  • 23
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.
Tristan Elliott
  • 594
  • 10
  • 8