How to show a custom composable placeholder using Coil in Jetpack Compose?
Asked Answered
B

2

5

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'
Beaverboard answered 3/11, 2021 at 0:46 Comment(0)
H
7

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
        ...
)
Husking answered 3/11, 2021 at 1:49 Comment(0)
K
6

Since Coil 2.0 there is a SubcomposeAsyncImage to solve your problem. Here is an example of how you can use it:

SubcomposeAsyncImage(
    model = "https://example.com/image.jpg",
    loading = {
        CircularProgressIndicator()
    },
    ...
)

For more information refer to the official documentation.

Kendre answered 24/8, 2023 at 17:25 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.