'Itemdecoration in Jetpack compose
I am currently in the process of evaluating whether or not we can migrate our rather complex UI to jetpack compose at this stage and I am struggling with the following problem.
I am having an infinite scrolling vertical List of various different conceptual components. Some of them are headers, then there can be some text, some horizontally scrolling (infinite) lists and then there are some grouped components that are also stacked vertically but conceptionally belong to a group.
@Compose
fun MyComplexList() {
LazyColumn {
item {
// some header
}
item {
// some horizontal content
LazyRow {
item {}
}
}
item {
// some other header
}
items(x) {
// Some text for each item
}
}
}
As one can see this thing is rather trivial to do using compose and a lot less code than writing this complex RecyclerView + Adapter...
with one exception: that background gradient, spanning (grouping) the Some infinite list of things
component. (the tilted gradient in the image)
In the past (:D) I would use an ItemDecoration
on the RecyclerView
to draw something across multiple items, but I can't find anything similar to that in Compose.
Does anyone have any idea on how one would achieve this with compose?
Solution 1:[1]
After your answer, this is what I understood...
@Composable
fun ListWithBg() {
val lazyListState = rememberLazyListState()
val itemsCount = 50
BoxWithConstraints(Modifier.fillMaxSize()) {
ListBg(lazyListState, itemsCount, maxHeight) // see below
LazyColumn(state = lazyListState, modifier = Modifier.fillMaxSize()) {
item {
Column(
Modifier
.fillMaxWidth()
.background(Color.White)
) {
Text(
text = "Some header",
style = MaterialTheme.typography.h5,
modifier = Modifier.padding(16.dp)
)
}
}
item {
Text(
text = "Some infinite list of things",
style = MaterialTheme.typography.h5,
modifier = Modifier.padding(16.dp)
)
}
items(itemsCount) {
Text(
text = "Item $it",
Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp, vertical = 6.dp)
.background(Color.LightGray)
.padding(8.dp)
)
}
}
}
}
and to change the background in according to the background, you can define something like the following:
@Composable
fun ListBg(lazyListState: LazyListState, itemsCount: Int, maxHeight: Dp) {
val firstVisibleIndex = lazyListState.firstVisibleItemIndex
val totalVisibleItems = lazyListState.layoutInfo.visibleItemsInfo.size
val hasNoScroll = itemsCount <= totalVisibleItems
val totalHeight = if (hasNoScroll) maxHeight else maxHeight * 3
val scrollableBgHeight = if (hasNoScroll) maxHeight else totalHeight - maxHeight
val scrollStep = scrollableBgHeight / (itemsCount + 2 - totalVisibleItems)
val yOffset = if (hasNoScroll) 0.dp else -(scrollStep * firstVisibleIndex)
Box(
Modifier
.wrapContentHeight(unbounded = true, align = Alignment.Top)
.background(Color.Yellow)
.offset(y = yOffset)
) {
Box(
modifier = Modifier
.fillMaxWidth()
.height(totalHeight)
.drawBehind {
drawRoundRect(
Brush.linearGradient(
0f to Color.Red,
0.6f to Color.DarkGray,
1.0f to Color.Green,
),
)
}
)
}
}
Here is the result:
Solution 2:[2]
One of the options:
Replace:
items(x) {
// Some text for each item
}
with:
item {
Column(modifier = Modifier.border(...).background(...)) { //Shape, color etc...
x.forEach {
// Some text for each item
}
}
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | bylazy |