Intro:
I’m building a simple app in Jetpack Compose. In the Home section of the app, I display a list of items. Nothing to fancy.
I do this using a custom card inside a LazyColumn
.
Issue:
When the app loads, the list is shown and then the items are shown for the first time. Then I scroll down and all the items are shown as expected in the custom card
.
The issue comes up when I do scroll up and then scroll down again, basically recomposing/rerendering the items.
Then the image
of the custom card ignores its contentScale
and its modifier
completely and breaks the layout. Something extremely odd.
What I have tried:
- I tried first to build the
custom card
withcolumns
androws
. - Then I built it with
ConstraintLayout
. - Tried to
remember
themodidier
.
What I am trying to achieve:
- A
custom card
where it has a definedheight
(180.dp) and afillMaxWidth
. - The
image
should be placed on thestart
of thecustom card
, its height should be fixed and the width as well (e.g. width: 124.dp, height: 180.dp).
Custom card code:
@Composable
fun ProductCard(
data: ProductDisplayData,
onClick: (ProductDisplayData) -> Unit = {}
) {
val constraints = ConstraintSet {
val imageSection = createRefFor("imageSection")
val textSection = createRefFor("textSection")
constrain(imageSection) {
top.linkTo(parent.top)
start.linkTo(parent.start)
end.linkTo(textSection.start)
width = Dimension.value(128.dp)
height = Dimension.value(180.dp)
}
constrain(textSection) {
top.linkTo(parent.top)
start.linkTo(imageSection.end)
bottom.linkTo(parent.bottom)
end.linkTo(parent.end)
width = Dimension.fillToConstraints
height = Dimension.fillToConstraints
}
}
ConstraintLayout(constraints, modifier = Modifier
.fillMaxWidth()
.clip(RoundedCornerShape(8.dp))
.padding(vertical = 8.dp)
.clickable { onClick(data) }
) {
if (data.image != null) {
Box(
modifier = Modifier
.layoutId("imageSection")
.height(180.dp)
.width(128.dp)
.clip(RoundedCornerShape(8.dp))
.clipToBounds()
) {
Image(
bitmap = data.image.asImageBitmap(),
contentDescription = "Product Image",
modifier = Modifier
.fillMaxSize()
)
}
}
Column(
modifier = Modifier
.layoutId("textSection")
.fillMaxWidth()
.padding(8.dp),
verticalArrangement = Arrangement.spacedBy(4.dp)
) {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
Text(
text = data.name,
fontWeight = FontWeight.Bold,
fontSize = 18.sp,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
modifier = Modifier.weight(1f)
)
Text(text = "${data.price}$" )
}
Text(text = data.brand, fontWeight = FontWeight.Bold, fontSize = 14.sp)
Text(text = data.size, modifier = Modifier, fontWeight = FontWeight.SemiBold, fontSize = 12.sp, fontStyle = FontStyle.Italic)
Text(text = data.category, fontWeight = FontWeight.SemiBold, fontSize = 12.sp)
LazyRow {
items(data.tags) { tag ->
Chip(
name = tag,
isSelected = false,
onSelectionChanged = {}
)
}
}
Text(
text = data.description,
maxLines = 2,
overflow = TextOverflow.Ellipsis,
fontWeight = FontWeight.Light,
fontSize = 12.sp
)
}
}
}
Images and graphic explanation of what’s going on:
-
This is the first time the item is shown in the LazyColumn
-
This is the second time, basically scrolled up and down again. In this case the contentScale has completely gone away.
-
Also look at the corner radius (.clip) of the image at the first time the item is shown.
-
The corner radius (.clip) is gone on the second time the item is shown, so basically also the modifiers are gone.
What is going on, please?