android Jetpack Compose中分页库的粘头

7tofc5zh  于 2023-02-27  发布在  Android
关注(0)|答案(3)|浏览(248)

我目前正在试用新的Jetpack compose UI工具包,我非常喜欢它。有一件事我不知道如何在由分页库填充的LazyColumn中使用stickyHeaders。文档中的非分页示例是:

val grouped = contacts.groupBy { it.firstName[0] }

fun ContactsList(grouped: Map<Char, List<Contact>>) {
    LazyColumn {
        grouped.forEach { (initial, contactsForInitial) ->
            stickyHeader {
                CharacterHeader(initial)
            }

            items(contactsForInitial) { contact ->
                ContactListItem(contact)
            }
        }
    }
}

因为我使用的是分页库,所以不能使用groupedBy,所以我尝试在PagingData上使用insertSeparators函数,并自己插入/创建头文件,如下所示(请忽略遗留的Date代码,它只是用于测试):

// On my flow
.insertSeparators { before, after ->
        when {
            before == null -> ListItem.HeaderItem(after?.workout?.time ?: 0)
            after == null -> ListItem.HeaderItem(before.workout.time)
            (Date(before.workout.time).day != Date(after.workout.time).day) ->
                ListItem.HeaderItem(before.workout.time)
            // Return null to avoid adding a separator between two items.
            else -> null
        }
    }

// In my composeable
LazyColumn {
    items(workoutItems) {
        when(it) {
            is ListItem.HeaderItem -> this@LazyColumn.stickyHeader { Header(it) }
            is ListItem.SongItem -> WorkoutItem(it)
        }
    }
}

但是这会产生一个我所有项的列表,并且头项会附加在末尾。在使用分页库时,什么是正确的stickyHeader函数使用方法?

inb24sb2

inb24sb21#

我通过查看items函数的源代码使其工作:在items函数中不能调用stickyHeader,根本不需要修改PagingData流程,只需要使用peek在不触发重载的情况下获取下一项,然后布局即可:

LazyColumn {
    val itemCount = workoutItems.itemCount
    var lastWorkout: Workout? = null

    for(index in 0 until itemCount) {
        val workout = workoutItems.peek(index)

        if(lastWorkout?.time != workout?.time) stickyHeader { Header(workout) }
        item { WorkoutItem(workoutItems.getAsState(index).value) } // triggers reload

        lastWorkout = workout 
    }
}
n1bvdmb6

n1bvdmb62#

我相信您的代码中的问题是您从LazyItemScope内部调用this@LazyColumn
我也用insertSeparators做了实验,得到了这个可以工作的LazyColumn代码:

LazyColumn {
    for (index in 0 until photos.itemCount) {
        when (val peekData = photos.peek(index)) {
            is String? -> stickyHeader {
                Text(
                    text = (photos.getAsState(index).value as? String).orEmpty(),
                )
            }
            is Photo? -> item(key = { peekData?.id }) {
                val photo = photos.getAsState(index).value as? Photo
                ...
            }
        }
    }
}
bzzcjhmw

bzzcjhmw3#

最新的解决方案是:

val lazyPagingItems = customersListPagingItems
for(index in 0 until lazyPagingItems.itemCount) {
    // important: use .peek() to get the item without causing page load
    when (val peekingItem = lazyPagingItems.peek(index)) {
        is Header -> stickerHeader(key=index or peekingItem.stableId) {
            // important: use .get() in composable to get the actual item and cause next page load
            val header = lazyPagingItems[index] as Header
            HeaderUi(header)
        }
        is Item -> item(key=index or peekingItem.stableId) {
            // important: use .get() in composable to get the actual item and cause next page load
            val item = lazyPagingItems[index] as Item
            ItemUi(item)
        }
    }
}

相关问题