Jfr*_*reu 7 header sticky android-jetpack-compose lazycolumn
我没有找到任何方法可以将 StickyHeader 与 LazyColumn 中的项目放在同一行:
因此,我使用 Box 将字母及其背景放在 LazyColumn 顶部,并使用 LazyListState 将其放在正确的位置:
@Preview
@Composable
fun InlineStickyList() {
val unsorted = listOf(...) // Pair("FirstName","LastName")
val data = unsorted.sortedBy { it.second[0] }
val groups = data.groupBy { it.second[0] }
@Composable
fun Person(pair: Pair<String, String>, showLetter: Boolean) {
Row(
modifier = Modifier
.fillMaxWidth()
.background(Color.White),
verticalAlignment = Alignment.CenterVertically
) {
Text(
"${pair.second[0]}",
modifier = Modifier
.padding(10.dp)
.alpha(if (showLetter) 1f else 0f),
fontSize = 20.sp
)
Text("${pair.first} ${pair.second}")
}
}
val state = rememberLazyListState()
Box(modifier = Modifier.fillMaxSize()) {
LazyColumn(modifier = Modifier.fillMaxSize(), state = state) {
groups.forEach { (_, group) ->
item {
Person(group[0], true)
}
items(group.subList(1, group.size)) {
Person(it, false)
}
}
}
}
val letter =
data[state.firstVisibleItemIndex].second[0]
val next =
data[state.firstVisibleItemIndex + 1].second[0]
Text(
"$letter",
fontSize = 20.sp,
modifier = Modifier
.clipToBounds()
.offset(y = if (letter != next) -with(LocalDensity.current) {
state.firstVisibleItemScrollOffset.toDp()
} else 0.dp)
.background(Color.White)
.padding(start = 10.dp, top = 10.dp, bottom = 10.dp),
)
}
Run Code Online (Sandbox Code Playgroud)
还有另一种方法可以实现这一目标吗?(更干净/更好)
我做了一个自定义实现...不确定这是否是最好的解决方案,但它是...
@Composable
fun LetterHeader(char: String, modifier: Modifier = Modifier) {
Text(
text = char,
color = Color(117, 137, 199),
fontSize = 28.sp,
modifier = modifier.padding(horizontal = 16.dp, vertical = 8.dp)
)
}
Run Code Online (Sandbox Code Playgroud)
上面的函数没有什么特别的。它代表一个充当“粘性标题”的字符,但它也将在项目列表中使用,如下所示。
@Composable
fun NameItem(
name: String,
showCharHeader: Boolean,
modifier: Modifier
) {
Row(Modifier.fillMaxWidth()) {
if (showCharHeader) {
LetterHeader(
char = name.first().toString(),
modifier = modifier
)
} else {
Spacer(modifier = modifier)
}
Text(
text = name,
color = Color.DarkGray,
fontSize = 14.sp,
modifier = Modifier.fillMaxWidth().padding(16.dp)
)
}
}
Run Code Online (Sandbox Code Playgroud)
上面的函数代表每个列表项。请注意,我们正在重用LetterHeader此处。它将有条件地显示。
最后,让我们看看名单...
@Composable
fun ListWithCustomStickHeaderScreen() {
Box(Modifier.fillMaxSize()) {
// List of names grouped by first char
val groupedNames = remember(names) {
names.groupBy { it.first() }
}
// Start indexes in the names list for each char
val startIndexes = remember(names) {
getStartIndexes(groupedNames.entries)
}
// End indexes in the names list for each char
val endIndexes = remember(names) {
getEndIndexes(groupedNames.entries)
}
// This commonModifier is used for both
// NameItem and LetterHeader
val commonModifier = Modifier.width(50.dp)
val listState = rememberLazyListState()
// We're going to move the stick header up in case of the
// first visible list index is one of last indexes
val moveStickyHeader by remember {
derivedStateOf {
endIndexes.contains(listState.firstVisibleItemIndex + 1)
}
}
LazyColumn(
modifier = Modifier.fillMaxSize(),
state = listState,
) {
itemsIndexed(names) { index, name ->
NameItem(
name,
// Showing the char header in the list item
// just in case it is one of the start indexes
// and it is not the first visible index
showCharHeader = startIndexes.contains(index) && listState.firstVisibleItemIndex != index,
commonModifier
)
}
}
LetterHeader(
char = names[listState.firstVisibleItemIndex].first().toString(),
modifier = commonModifier.then(
// Moving up the sticky header using offset modifier.
if (moveStickyHeader) {
Modifier.offset {
IntOffset(0, -listState.firstVisibleItemScrollOffset)
}
} else {
Modifier
}
)
)
}
}
Run Code Online (Sandbox Code Playgroud)
完整的代码可以在这里找到。
| 归档时间: |
|
| 查看次数: |
3618 次 |
| 最近记录: |