Loading local drawables with Coil Compose
Asked Answered
T

4

6

I recently migrated from Accompanist's ImagePainter to Coil's, below is the pertinent code after my updates.

val painter = rememberImagePainter(DRAWABLE_RESOURCE_ID)

when (painter.state) {
    is ImagePainter.State.Empty -> Timber.w("Empty")
    is ImagePainter.State.Loading -> {
        Box(
            contentAlignment = Alignment.Center,
            modifier = Modifier.wrapContentSize()
        ) {
            CircularProgressIndicator()
        }
    }
    is ImagePainter.State.Success -> {
        Image(
            painter = painter,
            contentDescription = null,
            contentScale = ContentScale.Fit,
            modifier = Modifier
                .padding(8.dp)
                .size(84.dp)
                .clip(RoundedCornerShape(corner = CornerSize(16.dp)))
        )
    }
    is ImagePainter.State.Error -> Timber.e("Error")
}

Now those images don't render and painter.state is always Empty. My legacy Accompanist implementation displayed images by this point in the code. It also works if I use the stock painterResource(resId) from Compose.

What am I missing to execute Coil's new painter through its states?

Taintless answered 26/8, 2021 at 4:9 Comment(0)
H
4

As suggested by @Philip Dukhov you don't need coil to load local resources.

If you want to use it, you can simply your code using:

val painter = rememberImagePainter(R.drawable.xxx)
val state = painter.state
Box(
    contentAlignment = Alignment.Center,
    modifier = Modifier.wrapContentSize()
) {
    AnimatedVisibility(visible = (state is ImagePainter.State.Loading)) {
        CircularProgressIndicator()
    }
    Image(
        painter = painter,
        contentDescription = null,
        modifier = Modifier.size(128.dp)
    )
}

enter image description here

Hadley answered 26/8, 2021 at 7:26 Comment(1)
rememberImagePainter is deprecated in favor of AsyncImagePainterAffra
E
14

You can use the drawable's resource ID as model for the coil's AsyncImage composable.

AsyncImage(
    model = R.drawable.bg_gradient,
    contentDescription = "Gradient background",
)

There's a significant performance difference between the composables - Image and AsyncImage. So Coil's AsyncImage loading is very handy at times.

Evieevil answered 1/8, 2022 at 17:40 Comment(0)
H
4

As suggested by @Philip Dukhov you don't need coil to load local resources.

If you want to use it, you can simply your code using:

val painter = rememberImagePainter(R.drawable.xxx)
val state = painter.state
Box(
    contentAlignment = Alignment.Center,
    modifier = Modifier.wrapContentSize()
) {
    AnimatedVisibility(visible = (state is ImagePainter.State.Loading)) {
        CircularProgressIndicator()
    }
    Image(
        painter = painter,
        contentDescription = null,
        modifier = Modifier.size(128.dp)
    )
}

enter image description here

Hadley answered 26/8, 2021 at 7:26 Comment(1)
rememberImagePainter is deprecated in favor of AsyncImagePainterAffra
P
3

You don't need coil to load local resources. You can use system painterResource:

Image(
    painter = painterResource(id = R.drawable.test),
    contentDescription = null,
    contentScale = ContentScale.Fit,
    modifier = Modifier
        .padding(8.dp)
        .size(84.dp)
        .clip(RoundedCornerShape(corner = CornerSize(16.dp)))
)

If you would use it for remove image loading: since move from accompanist to coil, painter won't start loading unless Image is in the view tree hierarchy. So you can move Image into a Box with your while:

Box(contentAlignment = Alignment.Center) {
    val painter = rememberImagePainter(R.drawable.test)
    Image(
        painter = painter,
        contentDescription = null,
        contentScale = ContentScale.Fit,
        modifier = Modifier
            .padding(8.dp)
            .size(84.dp)
            .clip(RoundedCornerShape(corner = CornerSize(16.dp)))
    )
    when (painter.state) {
        is ImagePainter.State.Empty -> Timber.w("Empty")
        is ImagePainter.State.Loading -> {
            Box(
                contentAlignment = Alignment.Center,
                modifier = Modifier.wrapContentSize()
            ) {
                CircularProgressIndicator()
            }
        }
        is ImagePainter.State.Success -> {

        }
        is ImagePainter.State.Error -> Timber.e("Error")
    }
}

Also it may not start loading when you're not providing enough size modifiers(that's not your case, just for you to know). Check out this answer for more information.

Preceptive answered 26/8, 2021 at 4:24 Comment(0)
T
0
val context = LocalContext.current
val imageLoader = ImageLoader(context)

val request = ImageRequest.Builder(context)
        .data(thumbnailUrl)
        .build()

val painter = rememberImagePainter(
        request = request,
        imageLoader = imageLoader
    )

val state = painter.state

Image(
  painter = painter,
  contentDescription = "thumbnail image",
  modifier = Modifier
            .fillMaxSize()
            .placeholder(
                visible = state is ImagePainter.State.Loading,
                color = PlaceholderDefaults.color(
                    backgroundColor = SMXTheme.colors.shimmer.copy(0.1f),
                ),
                highlight = PlaceholderHighlight.shimmer(),
            ),
        contentScale = ContentScale.Crop
    )
Trichite answered 16/2, 2022 at 3:31 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.