Jetpack compose - Border for Image reduces padding - android

#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
)
}
}

Related

How could i make this view like this in jetpack compose?

enter image description here
i still confused using component view in jetpack compose,
please help me for making this one. thanks
i was tried but it's not like current view in figma
Card(modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 20.dp)
.wrapContentHeight(), elevation = 8.dp,
shape = RoundedCornerShape(25.dp)
) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 4.dp)
.wrapContentHeight(),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween
) {
Image(painter = painterResource(id = R.drawable.ic_points_star_icon), modifier = Modifier
.padding(vertical = 8.dp)
.size(60.dp), contentDescription = "")
Column(modifier = Modifier
.weight(1f)
.padding(vertical = 8.dp), horizontalAlignment = Alignment.Start) {
Text(text = "Heading Text", style = AppTheme.typography.boldHeaderStyle)
Text(text = "This is sample body text", color = textColor.copy(0.4f), style = AppTheme.typography.captionTextStyle)
}
Button(
onClick = { /*Your on Click*/ },
shape = RoundedCornerShape(5.dp),
elevation = ButtonDefaults.elevation(
defaultElevation = 0.dp,
pressedElevation = 0.dp,
disabledElevation = 0.dp,
hoveredElevation = 0.dp,
focusedElevation = 0.dp,
),
colors = ButtonDefaults.buttonColors(
backgroundColor = BackArrowTint.copy(0.6f),
contentColor = Color.White
),
modifier = Modifier
.wrapContentHeight()
.padding(horizontal = 4.dp),
) {
Text(
text = "Buy Ticket",
modifier = Modifier.padding(vertical = 2.dp, horizontal = 4.dp),
color = White,
style = AppTheme.typography.buttonStyle,
)
}
}
}
Sample Image:

Ovelapping icons images in compose

I want to display the icons below so the center one is overlapping.
I am trying to use the Box but not sure how to arrange them so they are overlapping and in the center of the screen.
I have started using a Box with 3 Box stacked on each other. But not sure about how to arrange them so the center slightly overlaps the left and right icons. And slightly higher.
fun SurveyIconScreen() {
Box {
Box(modifier = Modifier
.clip(CircleShape)
.size(22.dp)
.background(color = Color.White),
contentAlignment = Alignment.Center) {
Icon(painter = painterResource(id = R.drawable.ic_star), contentDescription = "Star")
}
Box(modifier = Modifier
.clip(CircleShape)
.size(22.dp)
.background(color = Color.White),
contentAlignment = Alignment.Center) {
Icon(painter = painterResource(id = R.drawable.ic_cart), contentDescription = "Star")
}
Box(modifier = Modifier
.clip(CircleShape)
.size(22.dp)
.background(color = Color.White),
contentAlignment = Alignment.Center) {
Icon(painter = painterResource(id = R.drawable.ic_cart), contentDescription = "Star")
}
}
}
You can apply an offset modifier to overlap the icons.
Also use the zIndex(1f) modifier to drawn the icon in the center on top of all other icons.
Something like:
val shape = RoundedCornerShape(4.dp)
val borderColor = LightGray
Row(
modifier = Modifier.fillMaxWidth().height(70.dp),
horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically
){
Icon(Icons.Outlined.Star, contentDescription = "Star",
modifier = Modifier
.offset(x = 3.dp)
.size(32.dp)
.border(BorderStroke(1.dp,borderColor), shape)
.background(White)
)
Icon(
Icons.Outlined.ShoppingCart,
contentDescription = "Star",
modifier = Modifier
.zIndex(1f)
.offset(y = -12.dp)
.size(32.dp)
.border(BorderStroke(1.dp,borderColor), shape)
.background(White)
)
Icon(Icons.Outlined.Note, contentDescription = "Star",
modifier = Modifier
.offset(x = -3.dp)
.size(32.dp)
.border(BorderStroke(1.dp,borderColor), shape)
.background(White)
)
}

IconButton's content are not centered in Jetpack Compose

I am trying to build the following component.
Following is my code,
#Composable
fun View(modifier: Modifier = Modifier){
Row(modifier = Modifier
.fillMaxWidth()
.padding(16.dp),
horizontalArrangement = Arrangement.spacedBy(10.dp),
verticalAlignment = Alignment.CenterVertically) {
IconButton(onClick = { /*TODO*/ },
modifier = Modifier
.background(shape = roundShape, color = Color.Blue)
.size(40.dp)) {
Icon(
painter = painterResource(id = R.drawable.ic_microphone_2),
contentDescription = null,
tint = Color.White
)
}
BasicTextField(
value = "",
onValueChange = { },
modifier=Modifier
.height(40.dp)
.fillMaxWidth()
.border(1.dp,Color.Gray,roundShape)
)
}
The content of the IconButton is no longer centered after switching the LayoutDirection to Rtl.
CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Rtl) {
View()
}
this is the result of my code.
#Composable
fun IconView(modifier: Modifier = Modifier) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp),
horizontalArrangement = Arrangement.spacedBy(10.dp),
verticalAlignment = Alignment.CenterVertically
) {
Box(modifier = Modifier
.background(shape = RoundedCornerShape(20.dp), color = Color.Blue)
.size(50.dp).clickable {
}
){
Icon(
modifier = Modifier.align(alignment = Center),
painter = painterResource(id = android.R.drawable.ic_menu_call),
contentDescription = null,
tint = Color.White
)
}
BasicTextField(
value = "",
onValueChange = { },
modifier = Modifier
.height(40.dp)
.fillMaxWidth()
.border(1.dp, Color.Gray, RoundedCornerShape(20.dp))
)
}
}
Don't use iconButton as parent use Box and align child Icon to center. I Hope it will help you. Cheers

How to place items in row and one each above like position absolute with JetpackCompose?

I need to make layout that looks like this:
So I need to position two avatars in row while first avatar is going over second one. Also, icon for back is positioned on top of first avatar. I need basically something like position absolute but can not find how to do this with Jetpack compose.
You can use Box and zIndex to reach this result,
try this code you will get a result like that
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.background(Color.Yellow)
.padding(20.dp)
) {
Box {
Box(
contentAlignment = Alignment.TopStart,
modifier = Modifier
.height(30.dp)
.zIndex(3f)
) {
Icon(
imageVector = Icons.Rounded.ArrowBack,
contentDescription = "ArrowBack",
modifier = Modifier
.size(20.dp)
.clip(RoundedCornerShape(20.dp))
.background(Color.Gray)
.zIndex(2f)
.border(1.dp, Color.White, RoundedCornerShape(20.dp))
.padding(3.dp)
)
}
Box(
contentAlignment = Alignment.Center,
modifier = Modifier
.padding(start = 10.dp)
.size(30.dp)
.clip(RoundedCornerShape(20.dp))
.background(Color.Gray)
.zIndex(2f)
.border(1.dp, Color.White, RoundedCornerShape(20.dp))
.padding(6.dp)
) {
Icon(
imageVector = Icons.Rounded.Person,
contentDescription = "Person",
modifier = Modifier
.size(30.dp)
)
}
Box(
modifier = Modifier
.padding(start = 30.dp)
.size(30.dp)
.clip(RoundedCornerShape(20.dp))
.background(Color.Gray)
.zIndex(1f)
.border(1.dp, Color.White, RoundedCornerShape(20.dp))
.padding(6.dp)
) {
Icon(
imageVector = Icons.Rounded.Person,
contentDescription = "Person",
modifier = Modifier
.size(30.dp)
)
}
}
Spacer(modifier = Modifier.width(6.dp))
Text(text = "17 other answers")
}

How to achieve this layout in Jetpack Compose

I'm trying to use the new Jetpack Compose UI framework, but I'm running into an issue. I'd like to achieve this layout, which in xml is pretty easy to achieve:
But I can't figure out how to make the vertical divider take up the available vertical space, without specifying a fixed height. This code that I've tried doesn't seem to work:
#Composable
fun ListItem(item: PlateUI.Plate) {
Surface(
modifier = Modifier.fillMaxWidth(),
shape = RoundedCornerShape(8.dp),
elevation = 2.dp
) {
Row(
modifier = Modifier.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically
) {
Column(
modifier = Modifier
.padding(8.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(text = "Code")
Text(text = item.code)
}
Spacer(
modifier = Modifier
.preferredWidth(1.dp)
.background(color = MaterialTheme.colors.onSurface.copy(0.12f))
)
Spacer(modifier = Modifier.weight(1f))
Text(
modifier = Modifier
.padding(horizontal = 8.dp, vertical = 34.dp),
text = item.name
)
Spacer(modifier = Modifier.weight(1f))
}
}
}
I keep getting this result:
I also tried with ConstraintLayout, but it still didn't work
#Composable
fun ListItem(item: PlateUI.Plate) {
Surface(
modifier = Modifier.fillMaxWidth(),
shape = RoundedCornerShape(8.dp),
elevation = 2.dp
) {
ConstraintLayout(
modifier = Modifier.fillMaxWidth(),
) {
val(column, divider, text) = createRefs()
Column(
modifier = Modifier
.padding(8.dp)
.constrainAs(column){
top.linkTo(parent.top)
bottom.linkTo(parent.bottom)
start.linkTo(parent.start)
},
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(text = "Code")
Text(text = item.code)
}
Spacer(
modifier = Modifier
.preferredWidth(1.dp)
.background(color = MaterialTheme.colors.onSurface.copy(0.12f))
.constrainAs(divider){
top.linkTo(parent.top)
bottom.linkTo(parent.bottom)
start.linkTo(column.end)
}
)
Text(
modifier = Modifier
.padding(horizontal = 8.dp, vertical = 34.dp)
.constrainAs(text){
start.linkTo(divider.end)
end.linkTo(parent.end)
top.linkTo(parent.top)
bottom.linkTo(parent.bottom)
},
text = item.name
)
}
}
}
But nothing seems to work. Is this a bug, a missing feature or am I just missing something?
EDIT: Apparently the real problem is that the divider doesn't know how to measure when the Surface doesn't have a fixed height, setting height equal to some number solves the issue, but then the view doesn't adapt to the content height anymore, so this can't be the solution
You can apply:
the modifier .height(IntrinsicSize.Max) to the Row
the modifiers .width(1.dp).fillMaxHeight() to the Spacer
You can read more about the Intrinsic measurements here.
Something like:
Row(
modifier = Modifier.fillMaxWidth().height(IntrinsicSize.Max),
verticalAlignment = Alignment.CenterVertically
) {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
....
) {
Text(text = "....")
}
Spacer(
modifier = Modifier
.width(1.dp)
.fillMaxHeight()
.background(color = MaterialTheme.colors.onSurface.copy(0.12f))
)
Text(...)
}
You can set Intrinsic.Max for the preferredHeight of the Row, then set the Spacer to fill max height. You can read more on Intrinsics in this codelab section.
#Composable
fun ListItem() {
Surface(
modifier = Modifier.fillMaxWidth(),
shape = RoundedCornerShape(8.dp),
elevation = 2.dp
) {
Row(
modifier = Modifier.fillMaxWidth().preferredHeight(IntrinsicSize.Max),
verticalAlignment = Alignment.CenterVertically
) {
Column(
modifier = Modifier
.padding(8.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(text = "Code")
Text(text = "2456")
}
Spacer(
modifier = Modifier
.preferredWidth(1.dp)
.fillMaxHeight()
.background(color = Color.Black.copy(0.12f))
)
Spacer(modifier = Modifier.weight(1f))
Text(
modifier = Modifier
.padding(horizontal = 8.dp, vertical = 34.dp),
text = "Some name"
)
Spacer(modifier = Modifier.weight(1f))
}
}
}
I've solved it using constraint layout:
Box(modifier = Modifier.padding(Dp(50f))) {
ConstraintLayout(
modifier = Modifier
.border(width = Dp(1f), color = Color.Black)
.fillMaxWidth()
) {
val (left, divider, right) = createRefs()
Column(
modifier = Modifier
.padding(horizontal = Dp(20f))
.constrainAs(left) {
width = Dimension.wrapContent
start.linkTo(parent.start)
top.linkTo(parent.top)
end.linkTo(divider.start)
bottom.linkTo(parent.bottom)
}
) {
Text(text = "Code")
Text(text = "A12")
}
Box(
modifier = Modifier
.width(Dp(1f))
.background(Color.Black)
.constrainAs(divider) {
width = Dimension.wrapContent
height = Dimension.fillToConstraints
start.linkTo(left.end)
top.linkTo(parent.top)
end.linkTo(right.start)
bottom.linkTo(parent.bottom)
}
)
Box(
modifier = Modifier
.constrainAs(right) {
width = Dimension.fillToConstraints
start.linkTo(divider.end)
top.linkTo(parent.top)
end.linkTo(parent.end)
bottom.linkTo(parent.bottom)
}
) {
Text(
text = "Test",
modifier = Modifier
.padding(vertical = Dp(100f))
.align(Alignment.Center)
)
}
}
}
The key part is using that modifier height = Dimension.fillToConstraints
There are plenty of solutions here, but I thought I could demonstrate the ConstraintLayout approach and add a helpful usage of the IntrinsicSize enum that solves one of the issues (needing an adaptive height for the composable). Interestingly, either IntrinsicSize.Max or IntrinsicSize.Min will yield the desired behavior.
I used most of your code. The key differences are:
declares a guideline (my value passed in for the fraction does not produce the exact result you were looking for, but can be adjusted easily (use a fraction slightly smaller than .2) This can be useful if you expect wrapContent to alter your left Text to vary the location of a spacer, but would prefer a consistent spacer location across a list of these items.
others have mentioned, spacer modifier should include .fillMaxHeight()
define the height of the surface wrapper to be .height(IntrinsicSize.Min) docs ref here: https://developer.android.com/jetpack/compose/layout#intrinsic-measurements
divider start is constrained to the guideline
had to change the Spacer modifier to access the width, instead of preferredWidth
#Composable
fun ListItem(item: Plate) {
Surface(
modifier = Modifier.fillMaxWidth().height(IntrinsicSize.Min),
shape = RoundedCornerShape(8.dp),
elevation = 2.dp
) {
ConstraintLayout(
modifier = Modifier.fillMaxWidth(),
) {
val guideline = createGuidelineFromStart(0.2f)
val(column, divider, text) = createRefs()
Column(
modifier = Modifier
.padding(8.dp)
.constrainAs(column){
top.linkTo(parent.top)
bottom.linkTo(parent.bottom)
start.linkTo(parent.start)
end.linkTo(guideline)
},
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(text = "Code")
Text(text = item.code)
}
Spacer(
modifier = Modifier
.constrainAs(divider){
top.linkTo(column.top)
bottom.linkTo(column.bottom)
start.linkTo(guideline)
}
.width(1.dp)
.fillMaxHeight()
.background(color = MaterialTheme.colors.onSurface.copy(0.12f))
)
Text(
modifier = Modifier
.padding(horizontal = 8.dp, vertical = 34.dp)
.constrainAs(text){
start.linkTo(divider.end)
end.linkTo(parent.end)
top.linkTo(parent.top)
bottom.linkTo(parent.bottom)
},
text = item.name
)
}
}
}
I think Row layout is enough.
#Preview(showBackground = true, heightDp = 100)
#Composable
fun ListItem(item: PlateUI.Plate = PlateUI.Plate()) {
Card(
shape = RoundedCornerShape(8.dp)
) {
Row(
modifier = Modifier
.fillMaxSize(),
verticalAlignment = Alignment.CenterVertically
) {
Text(
modifier = Modifier.padding(8.dp),
text = "Code\n${item.code}",
textAlign = TextAlign.Center
)
Box(
Modifier
.fillMaxHeight()
.width(1.dp)
.background(color = MaterialTheme.colors.onSurface.copy(0.12f))
)
Text(
modifier = Modifier
.weight(1f)
.padding(8.dp),
text = item.name,
textAlign = TextAlign.Center
)
}
}
}

Categories

Resources