Hey all. I have a use case, where I need to hide ...
# compose
p
Hey all. I have a use case, where I need to hide a Text composable based on whether Coil has successfully downloaded the image from a URL or not. However, the current solution I came up with seems to cause infinite recompositions. Thread 👇
The code:
Copy code
@Composable
fun GameCover(
    title: String,
    imageUrl: String?,
    modifier: Modifier,
    onCoverClicked: () -> Unit
) {
    Card(
        modifier = modifier.clickable(onClick = onCoverClicked)
    ) {
        Box {
            var isTitleVisible by remember { mutableStateOf(true) }

            Image(
                painter = if (imageUrl == null) {
                    painterResource(R.drawable.game_cover_placeholder)
                } else {
                    rememberImagePainter(
                        data = imageUrl,
                        builder = {
                            placeholder(R.drawable.game_cover_placeholder)
                            error(R.drawable.game_cover_placeholder)
                            crossfade(durationMillis = 5000) // 5000 just for testing
                            listener(
                                onStart = { isTitleVisible = true },
                                onSuccess = { _, _ -> isTitleVisible = false },
                                onError = { _, _ -> isTitleVisible = true }
                            )
                        }
                    )
                },
                contentDescription = null,
                modifier = Modifier.matchParentSize(),
                contentScale = ContentScale.Crop,
            )

            if (isTitleVisible) {
                Text(
                    text = title,
                    modifier = Modifier.align(Alignment.Center),
                    color = colorResource(R.color.game_cover_title_text_color),
                )
            }
        }
    }
}
Now, when I change the
isTitleVisible
field inside Coil's listener methods (
onStart
,
onSuccess
,
onError
), two things happen: crossfade effect stops working as well as I believe this causes infinite recompositions (I've put some
Log
method calls inside
builder
lambda and in the logcat it's printed infinitely).
In the above code, if I remove
listener
method from the
builder
lambda, the crossfade starts working again as well as logcat does not print the log from the
builder
lambda indefinitely.
Any feedback would be greatly appreciated.
a
You don’t need
isTitleVisible
. You can use something like:
Copy code
val painter = if (imageUrl == null) {
    painterResource(R.drawable.game_cover_placeholder)
} else {
    rememberImagePainter(
        data = imageUrl,
        builder = {
            placeholder(R.drawable.game_cover_placeholder)
            error(R.drawable.game_cover_placeholder)
            crossfade(durationMillis = 5000) // 5000 just for testing
        }
    )
}

Image(
    painter = painter,
    contentDescription = null,
    modifier = Modifier.matchParentSize(),
    contentScale = ContentScale.Crop,
)

if (painter is ImagePainter && painter.state is ImagePainter.State.Success) {
    Text(
        text = title,
        modifier = Modifier.align(Alignment.Center),
        color = colorResource(R.color.game_cover_title_text_color),
    )
}
Also you should use the
Card(onClick = {})
overload instead of
clickable
modifier.
p
Thanks. I will try it out today's evening and let you know.
Yup, it's working as expected now by using the
ImagePainter.state
field. Thanks.
👍 1