Home > OS >  How to show a custom composable placeholder using Coil in Jetpack Compose?
How to show a custom composable placeholder using Coil in Jetpack Compose?

Time:11-03

I need to show a custom placeholder in Jetpack Compose using Coil, but that placeholder is not a drawable, it is a composable function that I customized. Is it possible to do this with the Coil? This is the code snippet where I use the Coil:

Image(
    modifier = Modifier
        .size(120.dp)
        .align(Alignment.CenterHorizontally),
    painter = rememberImagePainter(
        data = entry.imageUrl,
        builder = {
            crossfade(true)
            MyPlaceholder(resourceId = R.drawable.ic_video)
        },
    ),
    contentDescription = entry.pokemonName
)

This is my custom placeholder compose function:

@Composable
fun MyPlaceholder(@DrawableRes resourceId: Int) {
    Surface(
        modifier = Modifier.fillMaxSize(),
        color = Color(0xFFE0E0E0)
    ) {
        Box(
            modifier = Modifier.fillMaxSize(),
            contentAlignment = Alignment.Center,
        ) {
            Surface(
                modifier = Modifier.size(30.dp),
                shape = CircleShape,
                color = Color.White
            ) {
                Image(
                    modifier = Modifier
                        .padding(
                            PaddingValues(
                                start = 11.25.dp,
                                top = 9.25.dp,
                                end = 9.25.dp,
                                bottom = 9.25.dp
                            )
                        )
                        .fillMaxSize(),
                    painter = painterResource(id = resourceId),
                    contentDescription = null
                )
            }
        }
    }
}

My gradle (Coil):

// Coil
implementation 'io.coil-kt:coil-compose:1.4.0'

CodePudding user response:

Coil has no built-in support for composable placeholders.

You can put your composable inside Box and display the placeholder over Image depending on the state.

In my example I display it if the state is Loading or Error. You can add another view parameter for the Error case and use Crossfade instead of AnimatedVisibility.

Also I add Modifier.matchParentSize() to the Image to follow parent size calculated on the modifier parameter. You can't pass modifier parameter directly to Image, because modifiers like align only work for direct children, that's why you alway have to pass it to the container view.

@Composable
fun Image(
    painter: ImagePainter,
    placeholder: @Composable () -> Unit,
    contentDescription: String?,
    modifier: Modifier = Modifier,
    alignment: Alignment = Alignment.Center,
    contentScale: ContentScale = ContentScale.Fit,
    alpha: Float = DefaultAlpha,
    colorFilter: ColorFilter? = null,
) {
    Box(modifier) {
        Image(
            painter = painter,
            contentDescription = contentDescription,
            alignment = alignment,
            contentScale = contentScale,
            alpha = alpha,
            colorFilter = colorFilter,
            modifier = Modifier.matchParentSize()
        )

        AnimatedVisibility(
            visible = when (painter.state) {
                is ImagePainter.State.Empty,
                is ImagePainter.State.Success,
                -> false
                is ImagePainter.State.Loading,
                is ImagePainter.State.Error,
                -> true
            }
        ) {
            placeholder()
        }
    }
}

Usage:

Image(
    painter = rememberImagePainter(imageUrl),
    placeholder = {
        CustomComposableView(...)
    },
    contentDescription = "...",
    modifier = Modifier
        ...
)
  • Related