androidsvgandroid-jetpack-composecoil

Applying tint colour on an SVG loaded with Coil Compose Android


I'm trying to apply a tint colour using Compose, Coil 2.4 with SVG extension, but it does not really work.

SubcomposeAsyncImage(
    model = ImageRequest.Builder(LocalContext.current)
        .data("https://www.svgrepo.com/show/43967/colours-samples.svg")
        .decoderFactory(SvgDecoder.Factory())
        .crossfade(true)
        .build(),
    contentDescription = "",
    colorFilter = ColorFilter.tint(Color.Red)
) {
    when (painter.state) {
        is AsyncImagePainter.State.Error -> ImageErrorContent()
        is AsyncImagePainter.State.Loading -> ImageLoadingContent()
        else -> Image(
            painter = painter,
            contentDescription = contentDescription,
        )
    }
}

SubcomposeAsyncImage is from Coil.

I am using SubcomposeAsyncImage instead of other solutions such as coil.compose.AsyncImage or androidx.compose.material.Icon with Coil's image request builder because I need to override the loading and error states with different Composables.

This is a sample I made to showcase the issue. My expectation is that the downloaded image (black-outlined SVG) should be red. I tried with different blend modes but that didn't work.

is there any way to achieve the desired tinting with SVGs coming from a URL? It has worked fine with similar SVGs that were converted into a drawable using Compose's Icon/Image composables.

Thanks for the answers in advance :)


Solution

  • Edit:

    Since you are using Image() for showing the final data from async image,you need to add colorFilter to Image composable instead of SubcomposeAsyncImage

    Sample implementation with colorFilter:

    SubcomposeAsyncImage(
            model = ImageRequest.Builder(LocalContext.current)
                .data("https://www.svgrepo.com/show/43967/colours-samples.svg")
                .decoderFactory(SvgDecoder.Factory())
                .build(),
            modifier = Modifier
                .padding(horizontal = 16.dp, vertical = 4.dp)
                .size(50.dp),
            contentDescription = null
        ){
            when(painter.state){
                is AsyncImagePainter.State.Error -> {
                    // Error content
                }
                is AsyncImagePainter.State.Loading -> CircularProgressIndicator()
                else -> Image(
                    painter = painter,
                    contentDescription = contentDescription,
                    colorFilter = ColorFilter.tint(Color.Red)
                )
            }
        }
    
    

    Result with colorFilter:

    enter image description here