Raw Hasan
Raw Hasan

Reputation: 1396

Conditionally show image from the gallery or drawable resource using Coil and Jetpack Compose

I am trying to show an image from the gallery if anything chosen by the user, or an image from an image file in the drawable resource as the default image, which is not working. I am using Coil for Compose and added the dependency already. Here is the code:

class MainActivity : ComponentActivity() {
    private var imageUriState = mutableStateOf<Uri?>(null)

    private val selectImageLauncher = registerForActivityResult(GetContent()) { uri ->
        imageUriState.value = uri
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            ImageSourceActivityScreen()
        }
    }

    @Composable
    fun ImageSourceActivityScreen() {
        Column(
            modifier = Modifier.fillMaxSize(),
            verticalArrangement = Arrangement.Center
        ) {
            Image(
                painter = rememberImagePainter(
                    if (imageUriState != null) {
                        imageUriState.value
                    } else {
                        R.drawable.blank_profile_picture
                    }
                ),
                contentDescription = "profile image",
                contentScale = ContentScale.Crop,
                modifier = Modifier.fillMaxWidth()
            )
    ...
}

No error is showing, but the default image is also not showing. Please help to make it work. Thanks!

Upvotes: 2

Views: 2628

Answers (3)

Phil Dukhov
Phil Dukhov

Reputation: 87804

Your code doesn't work because you're comparing imageUriState with null which is always true

You have two options:

  1. Specify painter depending on your state value
Image(
    painter = if (imageUriState.value != null) {
        rememberImagePainter(
            imageUriState.value
        )
    } else {
        painterResource(id = R.drawable.blank_profile_picture)
    },
    contentDescription = "profile image",
    contentScale = ContentScale.Crop,
    modifier = Modifier.fillMaxWidth()
)
  1. By default, coil won't display you a placeholder if you pass null as data, which generally makes sense. If you wanna see your placeholder both when there's no image, and when you're waiting image to be loaded, you can create such function:
@Composable
inline fun rememberImagePainter(
    data: Any?,
    @DrawableRes emptyPlaceholder: Int,
    builder: ImageRequest.Builder.() -> Unit = {},
): Painter {
    val painter = rememberImagePainter(
        data,
        builder = {
            placeholder(emptyPlaceholder)
            builder()
        }
    )
    if (data == null) {
        return painterResource(emptyPlaceholder)
    }
    return painter
}

// usage
Image(
    painter = rememberImagePainter(
        "https://i.sstatic.net/rkyep.jpg",
        emptyPlaceholder = R.drawable.test,
    ),
    contentDescription = "profile image",
    contentScale = ContentScale.Crop,
    modifier = Modifier.fillMaxSize()
)

Upvotes: 4

Raw Hasan
Raw Hasan

Reputation: 1396

Found hints of where to look for the bug from @Gabriele Mariotti's answer. I was calling imageUriState without .value. Fixed that, and it is working now. Thanks, everyone for your help!

Image(
    painter = rememberImagePainter(
        if (imageUriState.value != null) {
            imageUriState.value
        } else {
            R.drawable.blank_profile_picture
        }
    ),
    contentDescription = "profile image",
    contentScale = ContentScale.Crop,
    modifier = Modifier.fillMaxWidth()
)

Upvotes: 0

Gabriele Mariotti
Gabriele Mariotti

Reputation: 363825

You can use the builder parameter to set a placeholder:

val painter = rememberImagePainter(
    imageUriState.value,
    builder = {
        placeholder(R.drawable.blank_profile_picture)
    }
)
Image(
    painter,
    contentDescription = "profile image",
    contentScale = ContentScale.Crop,
    modifier = Modifier.fillMaxWidth()
)

Upvotes: 0

Related Questions