Пользовательский липкий заголовок Jetpack Compose LazyRowAndroid

Форум для тех, кто программирует под Android
Ответить Пред. темаСлед. тема
Anonymous
 Пользовательский липкий заголовок Jetpack Compose LazyRow

Сообщение Anonymous »

При создании пользовательского интерфейса в Jetpack Compose возникла необходимость в прикрепленном заголовке для LazyRow. Но текущая реализация встроена в список как элемент строки.
Мне бы хотелось, чтобы прикрепленный заголовок находился над элементами, как здесь: Пример
UPD: Я начал пытаться решить проблему сам, но у меня возникли следующие проблемы:
Когда мой OffsetX находится в состоянии выхода, он прерывается при добавлении itemSpacing для LazyRow
Кроме того, с длинным StickyHeader я не могу понять, как правильно установить смещение, чтобы учитывать его длину.

Код: Выделить всё

@Composable
fun  LazyRowWithStickyHeader(
items: Map,
modifier: Modifier = Modifier,
state: LazyListState = rememberLazyListState(),
contentPadding: PaddingValues = PaddingValues(0.dp),
reverseLayout: Boolean = false,
horizontalArrangement: Arrangement.Horizontal = if (!reverseLayout) Arrangement.Start else Arrangement.End,
verticalAlignment: Alignment.Vertical = Alignment.Top,
flingBehavior: FlingBehavior = ScrollableDefaults.flingBehavior(),
userScrollEnabled: Boolean = true,
stickyHeader: StickyHeaderScope.(K) -> Unit,
itemContent: @Composable LazyItemScope.(V) -> Unit
) {
val itemsWithKeys = remember(items) {
items.flatMap { entry -> entry.value.map { entry.key to it } }
}
val textMeasurer = rememberTextMeasurer()
var itemWidth by remember { mutableIntStateOf(0) }
var stickyHeaderHeight by remember { mutableStateOf(0.dp) }

Box(
modifier = Modifier.drawWithCache {
onDrawBehind {
var previousKey: K? = null
val startPadding = state.layoutInfo.beforeContentPadding
if (itemWidth == 0) {
itemWidth = state.layoutInfo.visibleItemsInfo.firstOrNull()?.size ?: 0
}
state.layoutInfo.visibleItemsInfo.forEachIndexed { index, itemInfo ->
val currentKey = itemsWithKeys.getOrNull(itemInfo.index)?.first
val nextItemKey = itemsWithKeys.getOrNull(itemInfo.index + 1)?.first
if (currentKey == null || currentKey == previousKey) {
return@forEachIndexed
}

StickyHeaderScopeImpl(
drawScope = this,
textMeasurer = textMeasurer,
offsetProvider = { size ->
stickyHeaderHeight = size.height.toDp()
val offsetX = when {
//Stickying
currentKey == nextItemKey && index == 0 -> {
startPadding
}
//Coming
currentKey == nextItemKey -> {
(itemInfo.offset + startPadding).coerceAtLeast(startPadding)
}
//Leaving
else ->  {
itemInfo.offset + startPadding
}
}
Offset(x = offsetX.toFloat(), y = 0f)
}
).stickyHeader(currentKey)
previousKey = currentKey
}
}
}
) {
LazyRow(
modifier = modifier.padding(top = stickyHeaderHeight),
state = state,
contentPadding = contentPadding,
reverseLayout = reverseLayout,
horizontalArrangement = horizontalArrangement,
verticalAlignment = verticalAlignment,
flingBehavior = flingBehavior,
userScrollEnabled = userScrollEnabled
) {
items(
items = itemsWithKeys
) { (_, value) ->
itemContent(value)
}
}
}
}

fun StickyHeaderScope.drawStickyHeader(
text: String,
style: TextStyle,
color: Color = style.color,
overflow: TextOverflow = TextOverflow.Clip,
softWrap: Boolean = true,
maxLines: Int = Int.MAX_VALUE,
) {
val textLayout = textMeasurer.measure(
text = AnnotatedString(text),
style = style,
overflow = overflow,
softWrap = softWrap,
maxLines = maxLines
)
with(drawScope) {
drawText(
textLayoutResult = textLayout,
color = color,
topLeft = offsetProvider(textLayout.size)
)
}
}

interface StickyHeaderScope {
val drawScope: DrawScope
val textMeasurer: TextMeasurer
val offsetProvider: (IntSize) -> Offset
}

private class StickyHeaderScopeImpl(
override val drawScope: DrawScope,
override val textMeasurer: TextMeasurer,
override val offsetProvider: (IntSize) -> Offset
) : StickyHeaderScope
Демонстрация моей реализации: видео

Подробнее здесь: https://stackoverflow.com/questions/791 ... cky-header
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение
  • Пользовательский липкий заголовок Jetpack Compose LazyRow
    Anonymous » » в форуме Android
    0 Ответы
    12 Просмотры
    Последнее сообщение Anonymous
  • Пользовательский липкий заголовок Jetpack Compose LazyRow
    Anonymous » » в форуме Android
    0 Ответы
    18 Просмотры
    Последнее сообщение Anonymous
  • Пользовательский липкий заголовок Jetpack Compose LazyRow
    Anonymous » » в форуме Android
    0 Ответы
    10 Просмотры
    Последнее сообщение Anonymous
  • Пользовательский липкий заголовок Jetpack Compose LazyRow
    Anonymous » » в форуме Android
    0 Ответы
    9 Просмотры
    Последнее сообщение Anonymous
  • Пользовательский липкий заголовок Jetpack Compose LazyRow
    Anonymous » » в форуме Android
    0 Ответы
    9 Просмотры
    Последнее сообщение Anonymous

Вернуться в «Android»