I'm trying to fetch image uri and then display it in my application with coil.
var imageUri by remember { mutableStateOf<Uri?>(null) }
val launcher =
rememberLauncherForActivityResult(contract = ActivityResultContracts.GetContent()) { uri: Uri? ->
imageUri = uri
}
Column {
Button(onClick = {
//here we are going to add logic for picking image
launcher.launch(
"image/*"
)
}, content = {
Text(text = "Select Image From Gallery")
})
Log.d(TAG, "ClientCardItem: $imageUri")
Text(text = imageUri.toString())
I made this just to check if i fetched uri. I got result like this:
"content://com.android.providers.media.documents/document/image%3A18", i put it to string.
This is for image display:
Image(
painter = rememberImagePainter(
data = Uri.parse(uri) // or ht
)
,
contentDescription = "123",
modifier = Modifier.height(200.dp).width(200.dp),
contentScale = ContentScale.FillWidth
)
I know that I dont have .jpg or .png or something else to display it properly. My question is how to get that format to display picture I picked.
EDIT:
rememberAsyncImagePainter, rememberImagePainter or AsyncImage are not found ?
After I updated to:
implementation "io.coil-kt:coil:2.2.2"
On AsyncImage() -> Unresolved reference: AsyncImage
To display the image just use:
AsyncImage(model = imageUri, contentDescription = "Picture")
or:
Image(
painter = rememberAsyncImagePainter(imageUri),
contentDescription = "Picture",
)
Related
I want to show picture with Coil from Uri.
Following code shows picture but when I choose one.
I want to store Uri and when Screen starts i want to show it immediately.
val uri = "content://com.android.providers.media.documents/document/image%3A18".toUri()
var imageUri by remember { mutableStateOf<Uri?>(null) }
val context = LocalContext.current
val launcher =
rememberLauncherForActivityResult(contract = ActivityResultContracts.GetContent()) {
uri: Uri? ->
imageUri = uri
}
Column {
Button(onClick = {
//here we are going to add logic for picking image
launcher.launch(
"image/*"
)
}, content = {
Text(text = "Select Image From Gallery")
})
AsyncImage(
model = ImageRequest.Builder(context = context)
.data(imageUri)
.crossfade(true)
.build(),
contentDescription = "",
contentScale = ContentScale.Crop,
modifier = Modifier
.size(144.dp)
)
Image(
painter = rememberAsyncImagePainter(imageUri),
contentDescription = "Picture",
)
val uri is uri I chooshed before and I copied it and put to string to show image.
But this way first I need to choose picture and it will show. If I put uri instead of imageUri in .data() or rememberAsyncImagePainter nothing happens.
In my view model I have:
var uri = savedStateHandle.getStateFlow("uri", Uri.EMPTY)
private set
In my view:
val uri by viewModel.uri.collectAsState()
Image(
painter = rememberAsyncImagePainter(
ImageRequest
.Builder(LocalContext.current)
.data(data = uri)
.build()
),
contentDescription = "",
modifier = Modifier
.padding(vertical = 16.dp)
.size(avatarSize.value)
.clip(CircleShape)
,
contentScale = ContentScale.Crop
)
When I am saving new image it is saved with the same uri in local strage so my Image is not recomposed and old one is presented.
I can change uri and then image is recomposed as intended but how to inform my Image that it should be recomposed even when uri is still the same?
You can use coil's setParameter method on the builder which will reload whenever the parameter changes. You can use timestamp of last change as a parameter or something like that.
val timestamp by viewModel.timestamp.collectAsState()
ImageRequest
.Builder(LocalContext.current)
.data(data = uri)
.setParameter("timestamp", timestamp, null)
.build()
Let say i have image components can show image from selected image from gallery;
#Composable
fun ClickableToGalleryImage() {
var imageUri by remember {
mutableStateOf<Uri?>(null)
}
val launcher = rememberLauncherForActivityResult(
contract = ActivityResultContracts.GetContent()
) { uri: Uri? ->
println(imageUri)
imageUri = uri
}
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center
) {
Image(
painter = rememberAsyncImagePainter(
ImageRequest
.Builder(LocalContext.current)
.data(data = imageUri)
.build()
),
contentDescription = null,
modifier = Modifier
.clickable { launcher.launch("image/*") }
.size(100.dp)
.clip(CircleShape)
.border(2.dp, Color.Gray, CircleShape),
contentScale = ContentScale.Crop
)
}
}
this works very well.
But if i extract the imageUri value;
I/System.out: content://com.android.providers.media.documents/document/image%3A33
and manually type the imageUri variable;
Image(
painter = rememberAsyncImagePainter(
ImageRequest
.Builder(LocalContext.current)
.data(data = "content://com.android.providers.media.documents/document/image%3A33")
.build()
),
contentDescription = null,
modifier = Modifier
.size(100.dp)
.clip(CircleShape)
.border(2.dp, Color.Gray, CircleShape),
contentScale = ContentScale.Crop
)
Coil can't load picture. Why is that? And how can i show picture from gallery with uri?
Coil can't load picture. Why is that?
You do not have read permission to access the content.
And how can i show picture from gallery with uri?
Use the Uri that you get back from your ActivityResultContracts.GetContent request, in the same activity where you requested it.
If you need durable access to the content, switch to OpenDocument and call takePersistableUriPermission() on a ContentResolver, supplying the Uri.
I'm implementing a simple gallery screen using Jetpack Compose which shows all video and image thumbnails on the screen
I have displayed image from file path successfully. However, I've got trouble in showing video thumbnail. How can I do that using Coil?
Here's my code to show image thumbnails:
#Composable
fun ImageLoaderFromLocal(
url: String,
placeHolderResId: Int,
modifier: Modifier,
transformation: Transformation
) {
val painter = rememberImagePainter(data = File(url),
builder = {
placeholder(placeHolderResId)
crossfade(true)
transformations(transformation)
})
Image(
painter = painter,
contentDescription = null,
modifier = modifier,
contentScale = ContentScale.Inside
)
}
According to Coil documentation, you need to add following dependency:
implementation("io.coil-kt:coil-video:$coil_version")
and specify fetcher in the builder:
val context = LocalContext.current
val painter = rememberImagePainter(
data = url,
builder = {
fetcher(VideoFrameUriFetcher(context))
// optionally set frame location
videoFrameMillis(1000)
placeholder(placeHolderResId)
crossfade(true)
transformations(transformation)
}
)
The other answer doesn't really work any more.
so i tried this one and it worked
val context = LocalContext.current
var visible by rememberSaveable { mutableStateOf(false) }
val imageLoader = ImageLoader.Builder(context)
.components {
add(VideoFrameDecoder.Factory())
}.crossfade(true)
.build()
val painter = rememberAsyncImagePainter(
model = "Your file here",
imageLoader = imageLoader,
The painter should be called in the image composable
like this
Image(
painter = painter,
contentDescription = "",
contentScale = ContentScale.Crop,
alignment = Alignment.Center,
modifier = Modifier.fillMaxSize()
)
i hope this help someone
Coil accepts a drawable resource as an error placeholder. Is there a way to use an image URL here instead?
Here is the code I am working on:
// Global variables
var currentlySelectedImageUri = mutableStateOf<Uri?>(null)
var previousImageUri: Uri? = null
// #Composable fun() {...
Image(
painter = rememberImagePainter(
if (currentlySelectedImageUri.value != null) { // use the currently selected image
currentlySelectedImageUri.value
} else {
if (previousImageUri != null) { // use the previously selected image
previousImageUri
} else {
R.drawable.blank_profile_picture // use the placeholder image
}
}, builder = {
placeholder(R.drawable.blank_profile_picture)
error(R.drawable.blank_profile_picture) // FIXME: Set the previously selected image
}),
contentDescription = "profile image",
contentScale = ContentScale.Crop,
modifier = Modifier.fillMaxWidth()
)
In Coil 2.0.0 both AsyncImage and rememberAsyncImagePainter have error parameter that takes any other painter:
AsyncImage(
model = imageURL,
contentDescription = null,
error = painterResource(R.drawable.error)
)
Coil 1.4.0 version:
You can check painter.state value.
Initially it's ImagePainter.State.Empty, while image is loading it's ImagePainter.State.Loading, and if it failed - it becomes ImagePainter.State.Error. At this point you can change coil url, as an example, using local remember variable:
val localImagePainterUrl = remember { mutableStateOf<Uri?>(null) }
val painter = rememberImagePainter(
data = localImagePainterUrl.value
?: currentlySelectedImageUri.value
?: previousImageUri
?: R.drawable.blank_profile_picture,
builder = {
placeholder(R.drawable.blank_profile_picture)
})
val isError = painter.state is ImagePainter.State.Error
LaunchedEffect(isError) {
if (isError) {
localImagePainterUrl.value = previousImageUri
}
}
Image(
painter = painter,
...
)
There is a function inside coil ImageRequest Builder class
fun placeholder(#DrawableRes drawableResId: Int) = apply {
this.placeholderResId = drawableResId
this.placeholderDrawable = null
}
Usage:
Image(
painter = rememberImagePainter(
data = url,
builder = {
placeholder(R.drawable.your_placeholder_drawable) // or bitmap
}
)
)
UPDATE:
Also use: com.google.accompanist.placeholder
Dependency gradle: com.google.accompanist:accompanist-placeholder:accompanist_version
// accompanist_version = 0.19.0
Modifier.placeholder(
visible = true/false,
color = color,
highlight = PlaceholderHighlight.shimmer(color),
shape = imageShape // RectangleShape)
Actually there is an easier way from coil compose api , you can just add error(R.drawable.your_placeholder_drawable) to the builder and that's it
Image(painter = rememberImagePainter(data = url, builder = {error(R.drawable.your_placeholder_drawable)}))