I need to display image from uri/filepath, big image 1300x1600 resolution.
Need to maintain aspect ratio.
i tried with coil but didn't give desirable result, still shows big image. not sure whats wrong
here what i tried
val painter =
rememberAsyncImagePainter(imageUri.value)
Image(
painter = painter,
contentScale = ContentScale.Fit,
contentDescription = null,
modifier = Modifier
.padding(16.dp, 0.dp, 16.dp, 0.dp)
.fillMaxWidth()
.aspectRatio(painter.intrinsicSize.height / painter.intrinsicSize.width)
)
You are getting size unspecified if one of view width/height is calculated as zero.
You can use something like:
Image(
painter = painter,
contentScale = ContentScale.Fit,
contentDescription = "contentDescription",
modifier = Modifier
.padding(16.dp, 0.dp, 16.dp, 0.dp)
.fillMaxWidth()
.then(
(painter.state as? AsyncImagePainter.State.Success)
?.painter
?.intrinsicSize
?.let { intrinsicSize ->
Modifier.aspectRatio(intrinsicSize.width / intrinsicSize.height)
} ?: Modifier
)
)
Related
I have a simple compose UI using Image composable. Whenever I set the little image to my composable size, the image does not crop properly and some paddings showed. My drawable size is 125x125 and my composable size is 350dp. Here is my code example:
Image(
painter = painterResource(id = R.drawable.sample_image_2),
contentDescription = "Player Main Image",
modifier = Modifier
.size(350.dp)
.border(BorderStroke(1.dp, Color.Green))
.clip(RoundedCornerShape(10))
.align(CenterHorizontally)
.padding(0.dp)
.clickable { },
contentScale = ContentScale.Crop,
)
Consider the following image:
I have a Column that has an Image together with another Column that has some Text elements. What I'm trying to do is to have the Image scale uniformly to the available space. I just can't make it work.
Column(
modifier = Modifier
.fillMaxSize()
.background(Color.Cyan)
.padding(horizontal = 16.dp),
verticalArrangement = Arrangement.SpaceEvenly
) {
Image(
modifier = Modifier.fillMaxWidth(),
painter = painterResource(R.drawable.rocket_boy),
contentDescription = null,
contentScale = ContentScale.Fit
)
Column(
modifier = Modifier.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally
) {
repeat(20) {
Text(text = "${it}")
}
}
}
One of the things that I tried was setting the size of the Image to fillMaxSize and the weight of the second Column to 1f, but it didn't do anything. Maybe I need to have the size of the second Column fixed? Any help is very appreciated.
You haven't used Modifier.weight on the correct child. It should be applied to the view, which you need to fill the rest of the parent.
The parent will divide the vertical space remaining after measuring unweighted child elements and distribute it according to this weight.
Modifier.weight has argument fill with default parameter true. This default parameter works same as Modifier.fillMaxHeight() (in case of Column), if you don't need to fill all height available, you can specify false:
Column(
modifier = Modifier
.fillMaxSize()
.background(Color.Cyan)
.padding(horizontal = 16.dp),
verticalArrangement = Arrangement.SpaceEvenly,
horizontalAlignment = Alignment.CenterHorizontally,
) {
val painter = painterResource(R.drawable.ic_redo)
Image(
modifier = Modifier.weight(1f, fill = false)
.aspectRatio(painter.intrinsicSize.width / painter.intrinsicSize.height)
.fillMaxWidth(),
painter = painter,
contentDescription = null,
contentScale = ContentScale.Fit
)
Column(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier.fillMaxWidth()
) {
repeat(20) {
Text(text = "${it}")
}
}
}
It seems to your image size is less than the screen max width, for that reason the container of the image fill the width, but the image remains small, if you fill the height on the image it scales correctly but the image container fills all space leaving below the list. You could try setting and aspect ratio to the modifier to prevent container from filling all available space:
...
val painter = painterResource(id = R.drawable.ic_dismiss_24)
Image(
modifier = Modifier
.aspectRatio(ratio = painter.intrinsicSize.height /
painter.intrinsicSize.width)
.fillMaxWidth()
.fillMaxHeight(),
painter = painter,
contentDescription = null,
contentScale = ContentScale.Fit
)
...
Couldn't get it work right using a Column, but I succeeded using a ConstraintLayout and Nestor's help with the aspectRatio.
ConstraintLayout(
modifier = Modifier.fillMaxSize()
) {
val (button, text) = createRefs()
val painter = painterResource(R.drawable.rocket_boy)
Image(
modifier = Modifier
.aspectRatio(ratio = painter.intrinsicSize.width /
painter.intrinsicSize.height)
.padding(16.dp)
.constrainAs(text) {
top.linkTo(parent.top)
bottom.linkTo(button.top)
height = Dimension.preferredWrapContent
width = Dimension.preferredWrapContent
start.linkTo(parent.start)
end.linkTo(parent.end)
},
painter = painter,
contentDescription = null,
contentScale = ContentScale.Fit
)
Column(Modifier.constrainAs(button) {
bottom.linkTo(parent.bottom, margin = 16.dp)
top.linkTo(text.bottom)
start.linkTo(parent.start)
end.linkTo(parent.end)
height = Dimension.wrapContent
}) {
repeat(5) {
Text(text = "$it")
}
}
}
But if someone thinks that it can still be done with a Column instead of a ConstraintLayout, he can post an answer and I may accept it.
If we consider the height of the parent Column - as the sum of the heights of the Image and the nested Column - it can be argued that the height of your Image should be equal to the remainder of the height, after subtracting from the height of the parent Column - the height of the nested Column.
var textInColumnSize by remember { mutableStateOf(Size.Zero) }
var globalColumnSize by remember { mutableStateOf(Size.Zero) }
val imageHeight: Dp =
LocalDensity.current.run { (globalColumnSize.height -
textInColumnSize.height).toDp() }
Column(
modifier = Modifier
.fillMaxSize()
.onGloballyPositioned { coordinates ->
globalColumnSize = coordinates.size.toSize()
}
.background(Color.Cyan)
.padding(horizontal = 16.dp),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.SpaceEvenly
) {
Image(
modifier = Modifier
.fillMaxWidth()
.height(imageHeight),
painter = painterResource(R.drawable.rocket_boy),
contentDescription = null,
)
Column(
modifier = Modifier
.fillMaxWidth()
.onGloballyPositioned { coordinates ->
textInColumnSize = coordinates.size.toSize()
},
horizontalAlignment = Alignment.CenterHorizontally
) {
repeat(10) {
Text(text = "$it")
}
}
}
I am trying to learn jetpack compose and I've learnt to use spacer for items, but I still do not know how to add margin to an image on the left or right, any idea?
Screen:
code:
Column(
modifier = Modifier.fillMaxSize()
) {
Spacer(modifier = Modifier
.padding(50.dp)
)
Image(
painter = painterResource(id = R.drawable.image),
contentDescription = null,
contentScale = ContentScale.Crop,
modifier = Modifier
.size(80.dp)
.clip(CircleShape)
)
}
There is actually almost uncountable different ways to achieve this , I would using a Row() instead of a Column() in your case and simply add a spacer with your needed space as follows
Spacer(modifier = Modifier.width(50.dp))
or if you want to align the image to the left with the same approach your function would look like that
Row(
modifier = Modifier.fillMaxSize()
) {
Spacer(modifier = Modifier.weight(1f))
Image(
painter = painterResource(id = R.drawable.ic_image),
contentDescription = null,
contentScale = ContentScale.Crop,
modifier = Modifier
.size(80.dp)
.clip(CircleShape)
)
}
How can we achieve this kind of layout in jetpack compose?
I am interested in positioning the round picture 'GD', on top of the header image like it is here. I tried to use Box layout like this
Box(
modifier = Modifier
.fillMaxWidth()
.fillMaxHeight()
) {
Column(){
Coil(
modifier = Modifier
.fillMaxWidth()
.height(200.dp),
)
}
Coil(
modifier = Modifier
.height(120.dp)
.width(120.dp)
.padding(top = 140.dp, start = 20.dp)
.clip(CircleShape),
contentScale = COntentScale.Crop
)
}
but this is not taking correct shape.
Thanks.
You can use a Box.
Align the circular in the Box with the align(BottomStart) modifier and then apply an offset and finally clip the Image in a CircleShape.
Something like:
Box(Modifier.padding(top=40.dp)){
Image(
painterResource(/* ... */ ),
"contentDescription",
)
Image(
painter = rememberImagePainter("...."),
modifier = Modifier
.height(50.dp)
.width(50.dp)
.align(BottomStart) //align in the Box
.offset(12.dp, 25.dp) //apply an offset
.clip(CircleShape) //clip the image
.border(color= White, shape = CircleShape, width= 2.dp),
contentDescription = "",
contentScale = ContentScale.Crop
)
Note: rememberImagePainter requires the coil-compose implementation.
Created ImageCard view for creating the list in android jetpack compose
but some images can't scratch to Box widget's width and height.
Using 640*427 image and output like image 1.
Using 6720*4480 image and it's looking good like image 2.
Use below code to create ImageCard.
Usage of ImageCard function: Call ImageCardData function in setContent{} function
#Composable
fun ImageCard(
painter: Painter,
title: String,
contentDescription: String,
modifier: Modifier = Modifier
) {
Card(
modifier = modifier.fillMaxWidth(),
shape = RoundedCornerShape(10.dp),
elevation = 5.dp
) {
Box(
modifier = Modifier.height(200.dp)
) {
Image(
painter = painter,
contentDescription = contentDescription,
contentScale = ContentScale.Crop
)
Box(
modifier = Modifier
.fillMaxSize()
.background(
brush = Brush.verticalGradient(
colors = listOf(
Color.Transparent,
Color.Black
),
startY = 50f
)
)
)
Box(
modifier = Modifier
.fillMaxSize()
.padding(12.dp),
contentAlignment = Alignment.BottomStart
) {
Text(
text = title,
style = TextStyle(color = Color.White, fontSize = 16.sp)
)
}
}
}
}
#Composable
fun ImageCardData() {
val painter = painterResource(id = R.drawable.engagement)
val title = "Sample Text Title"
val description = "This is sample Image Description"
Box(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp)
) {
ImageCard(
painter = painter,
title = title,
contentDescription = description
)
}
}
Your image view size gets calculated by it content, because it doesn't have any size modifiers.
Add fillMaxSize to the image:
Image(
painter = painter,
contentDescription = contentDescription,
contentScale = ContentScale.Crop,
modifier = Modifier.fillMaxSize()
)
It depends by the Image implementation with a Painter
Creates a composable that lays out and draws a given Painter. This will attempt to size the composable according to the Painter's intrinsic size. However, an optional Modifier parameter can be provided to adjust sizing or draw additional content (ex. background)
It means that using an 640*427 image in a parent container with larger dimensions the Image composable size is the original size of the Painter.
The scale factor applied by the ContentScale is based on these dimensions and source = destination and doesn't change the intrinsic size of the original Painter.
Image(
painter = painter,
contentDescription = contentDescription,
contentScale = ContentScale.Crop
)
Using a 6720*4480 image the Image size is larger than the parent container and in this way the Image composable fills all the available space.
In your case you can solve using the modifier fillMaxWidth() in your Image
Image(
modifier =Modifier.fillMaxWidth(),
painter = painter,
contentDescription = contentDescription,
contentScale = ContentScale.Crop
)
In this way the Image composable fills the parent space.