I'm trying to achieve this view with jetpack compose:
I create a row consisting of an image with a weight 0.7 and a column that contains those smaller images with a weight 0.3.
But there is always padding at bottom of the column and they won't align perfectly.
My code:
#Composable
fun TrendingSection() {
Row(horizontalArrangement = Arrangement.SpaceBetween) {
Image(
painter = painterResource(id = R.drawable.shadmehr),
contentDescription = "First trending music",
modifier = Modifier
.weight(0.7f)
.padding(4.dp)
.clip(RoundedCornerShape(16.dp))
)
Column(
verticalArrangement = Arrangement.SpaceAround,
modifier = Modifier
.weight(0.3f)
) {
Image(
painter = painterResource(id = R.drawable.shadmehr),
contentDescription = "First trending music",
modifier = Modifier
.padding(4.dp)
.clip(RoundedCornerShape(16.dp))
)
Image(
painter = painterResource(id = R.drawable.shadmehr),
contentDescription = "First trending music",
modifier = Modifier
.padding(4.dp)
.clip(RoundedCornerShape(16.dp))
)
}
}
}
Anyone knows what is the problem or know a better solution for doing this?
Result:
Related
I want to make same Image size in all pages of HorizontalPager. I am manually added size in Image and it looks perfect. I want to remove the specific size, so is it possible to do in jetpack compose?
HorizontalPager(
count = 5,
state = pagerState,
) { currentPage ->
Column(horizontalAlignment = Alignment.CenterHorizontally) {
Column(
Modifier.height(height = 428.dp),
horizontalAlignment = Alignment.CenterHorizontally,
) {
Image(
modifier = Modifier
.size(280.dp)
.padding(top = 80.dp),
painter = painterResource(imageResId),
contentDescription = null,
contentScale = ContentScale.Fit,
)
Text(
modifier = Modifier.padding(top = 20.dp),
text = "Xyz",
)
Text(
modifier = Modifier.padding(top = 20.dp),
text = "description",
textAlign = TextAlign.Center,
)
}
HorizontalPagerIndicator(
modifier = Modifier
.padding(top = 80.dp),
pagerState = pagerState,
activeColor = Teal,
inactiveColor = Platinum,
)
}
}
Image uses intrinsic size of Bitmap/Painter, parent Constraints or dimensions in simple manner and ContentScale to draw a resource.
Based on image resource aspect ratios they are to be fit inside an Image constrained with 428.dp minus size of other Text composables, this is the biggest height Image can get based on its inner calculations. Simple solution for this is to match one dimension of Image to parent and using Modifier.aspectRatio to have all images have same dimensions without setting a fixed size modifier.
These 2 png files have different aspect ratios and drawn as
#Preview
#Composable
private fun Test(){
Column(modifier = Modifier.fillMaxSize()) {
Column(modifier = Modifier.height(200.dp).border(2.dp, Color.Red)) {
Image(
painter = painterResource(id = R.drawable.landscape11),
contentDescription = null,
contentScale = ContentScale.Fit
)
}
Column(modifier = Modifier.height(200.dp).border(2.dp, Color.Green)) {
Image(
painter = painterResource(id = R.drawable.landscape3),
contentDescription = null,
contentScale = ContentScale.Fit
)
}
}
}
After setting aspect ratio modifier
#Preview
#Composable
private fun Test(){
Column(modifier = Modifier.fillMaxSize()) {
Column(modifier = Modifier.height(200.dp).border(2.dp, Color.Red)) {
Image(
modifier = Modifier.aspectRatio(4/3f),
painter = painterResource(id = R.drawable.landscape11),
contentDescription = null,
contentScale = ContentScale.Fit
)
}
Column(modifier = Modifier.height(200.dp).border(2.dp, Color.Green)) {
Image(
modifier = Modifier.aspectRatio(4/3f),
painter = painterResource(id = R.drawable.landscape3),
contentDescription = null,
contentScale = ContentScale.Fit
)
}
}
}
#Composable
fun BottomStrip() {
Row(modifier = Modifier
.fillMaxWidth()
.height(70.dp)
.background(color = colorResource(id = R.color.cgux_background_grey)),
horizontalArrangement = Arrangement.End, verticalAlignment = Alignment.CenterVertically) {
Image(
painter = painterResource(id = R.drawable.cgux_ic_keyboard_16),
modifier = Modifier
.width(36.dp)
.height(36.dp)
.border(BorderStroke(1.dp, colorResource(id = R.color.cgux_primary_500_base)))
.padding(5.dp)
.clickable {},
contentDescription = "Expandable Image",
colorFilter = ColorFilter.tint( colorResource(id = R.color.cgux_primary_500_base))
)
}
}
I have a composable function as above . My idea is to align image to right of Row with some padding on all sides of Image.
I also have to create border around image , which I did using border modifier.
The problem I'm facing is when I set border to Image , the padding is lost which means I don't see padding for Image. Image touch right end of the screen.Is there a way we can have padding for border as well.?
Adding the padding before border will solve your problem. Below is the full code.
#Composable
fun BottomStrip() {
Row(modifier = Modifier
.fillMaxWidth()
.height(70.dp)
.background(color = colorResource(id = R.color.cgux_background_grey)),
horizontalArrangement = Arrangement.End, verticalAlignment = Alignment.CenterVertically) {
Image(
painter = painterResource(id = R.drawable.cgux_ic_keyboard_16),
modifier = Modifier
.width(36.dp)
.height(36.dp)
.padding(5.dp)
.border(BorderStroke(1.dp, colorResource(id = R.color.cgux_primary_500_base)))
.padding(5.dp)
.clickable {},
contentDescription = "Expandable Image",
colorFilter = ColorFilter.tint( colorResource(id = R.color.cgux_primary_500_base))
)
}
}
In jetpack compose the order of modifiers is important. Official doc
You can use this solution and add padding before setting size for your image:
#Composable
fun BottomStrip() {
Row(modifier = Modifier
.fillMaxWidth()
.height(70.dp)
.background(color = colorResource(id = R.color.cgux_background_grey)),
horizontalArrangement = Arrangement.End, verticalAlignment = Alignment.CenterVertically) {
Image(
painter = painterResource(id = R.drawable.cgux_ic_keyboard_16),
modifier = Modifier
.padding(5.dp) // padding between Row and Image, you can remove it because you already set size for Image and Row
.border(BorderStroke(1.dp, colorResource(id = R.color.cgux_primary_500_base)))
.padding(5.dp) // padding between border and image
.size(36.dp)
.clickable {},
contentDescription = "Expandable Image",
colorFilter = ColorFilter.tint( colorResource(id = R.color.cgux_primary_500_base))
)
}
}
You can try like below.
#Composable
fun BottomStrip() {
Row(
modifier = Modifier
.fillMaxWidth()
.height(70.dp)
.background(color = Color.Cyan),
horizontalArrangement = Arrangement.End, verticalAlignment = Alignment.CenterVertically
) {
Image(
painter = painterResource(id = R.drawable.ic_visa),
modifier = Modifier
.padding(5.dp)
.border(BorderStroke(1.dp, Color.Red))
.clickable {},
contentDescription = null
)
}
}
I am trying to have a splash screen in our application and I got stuck Abit with the jetpack Compose design. So I want to have a background gradient, I am now using the image which does not fit well in the phone and want to center my logo and text in the middle of the screen how can I achieve that. Mostly centering since I have tried the gradient part and I have no success. Here is my code
Here is my background component
#Composable
fun BackgroundComponents(
#DrawableRes backgroundDrawableRes: Int,
contentDescription: String?,
modifier: Modifier = Modifier,
painter: Painter,
alignment: Alignment = Alignment.Center,
) {
Box(
modifier = modifier
) {
Image(
painter = painterResource(id = backgroundDrawableRes),
contentDescription = contentDescription,
modifier = modifier.matchParentSize()
)
Box(
contentAlignment = Alignment.Center
) {
Image(
painter = painter,
contentDescription = contentDescription,
alignment = alignment
)
}
Text(
modifier =
modifier.padding(top = 36.dp),
text = "Hello and welcome to our app",
color = (colorResource(id = R.color.white)),
fontSize = 16.sp,
)
}
}
This is how I am calling it on the Screen
#Composable
fun Splash(modifier: Modifier = Modifier) {
Column(modifier = modifier.fillMaxSize()) {
BackgroundComponents(
backgroundDrawableRes = R.drawable.ic_launcher_foreground,
contentDescription = "",
modifier = modifier.fillMaxSize(),
painter = painterResource(id = coil.base.R.drawable.notification_bg)
)
}
}
I would like to push the icon and text in the middle and centered, also instead of using an image can I draw that gradient?
You can apply the gradient to the parent Box as background modifier and then just apply the expected alignment to the composable inside the Box.
Something like:
Box(
modifier = Modifier
.fillMaxSize()
.background(
Brush.horizontalGradient(
colors = listOf(
Color.Blue,
Teal200
)
)
),
contentAlignment = Alignment.Center
) {
Column(horizontalAlignment = Alignment.CenterHorizontally) {
Image(
painter = painterResource(id = R.drawable.xx),
contentDescription = "contentDescription",
)
Spacer(Modifier.height(36.dp))
Text(
text = "Hello and welcome to our app",
color = White,
fontSize = 16.sp,
)
}
}
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)
)
}