Jetpack Compose Paging With Header

Modify sample code from Jetpack Compose Paging Sample.

Modify MemberRepository to generate age in sequence.

class MemberRepository(val totalCount: Int, val pageSize: Int) {    suspend fun getMembers(page: Int): List<Member> {        val random = Random(page)        val startIndex = (page - 1) * pageSize + 1        var endIndex = startIndex + pageSize - 1        if (endIndex > totalCount) {            endIndex = totalCount        }        return  (startIndex..endIndex).map { index ->            // Member(name = "Member #${index}", age = random.nextInt(1, 99))            Member(name = "Member #${index}", age = index)        }    }}

Sample using Sticky Header

@ExperimentalFoundationApi@Composablefun MemberScreen(viewModel: MemberViewModel = viewModel()) {    val lazyMembers = viewModel.membersFlow.collectAsLazyPagingItems()    LazyColumn {        val itemCount = lazyMembers.itemCount        var lastAgeGroup: Int? = null        for (index in 0 until itemCount) {            val nextMember = lazyMembers.peek(index)            if (nextMember != null) {                val age = nextMember.age                // create a header for every 10y of age                if (lastAgeGroup == null || age > lastAgeGroup) {                    lastAgeGroup = (lastAgeGroup ?: 0) + 10                    val ageGroup = lastAgeGroup                    stickyHeader(key = ageGroup) {                        Text("<= $ageGroup")                    }                }            }            val member = lazyMembers[index]            if (member != null) {                item(key = member.name) {                    Text("${member.name}, age=${member.age}")                }            }        }    }}

Sample using Text as header.

@ExperimentalFoundationApi@Composablefun MemberScreen(viewModel: MemberViewModel = viewModel()) {    val lazyMembers = viewModel.membersFlow.collectAsLazyPagingItems()    LazyColumn {        val itemCount = lazyMembers.itemCount        var lastAgeGroup: Int? = null        for (index in 0 until itemCount) {            val nextMember = lazyMembers.peek(index)            var ageGroup: Int? = null            if (nextMember != null) {                val age = nextMember.age                if (lastAgeGroup == null || age > lastAgeGroup) {                    lastAgeGroup = (lastAgeGroup ?: 0) + 10                    ageGroup = lastAgeGroup                }            }            val member = lazyMembers[index]            if (member != null) {                item(key = member.name) {                    if (ageGroup != null) {                        Text("< $ageGroup")                    }                    Text("${member.name}, age=${member.age}")                }            }        }    }}

Alternatively, you can also group data together before render them.

@ExperimentalFoundationApi@Composablefun MemberScreen(viewModel: MemberViewModel = viewModel()) {    val lazyMembers = viewModel.membersFlow.collectAsLazyPagingItems()    val memberGroup = mutableMapOf<String, MutableList<Int>>()    val itemCount = lazyMembers.itemCount    var lastAgeGroup: Int? = null    // to fill up memberGroup, will not trigger any render    for (index in 0 until itemCount) {        val nextMember = lazyMembers.peek(index)        var ageGroup: Int? = null        if (nextMember != null) {            val age = nextMember.age            if (lastAgeGroup == null || age > lastAgeGroup) {                lastAgeGroup = (lastAgeGroup ?: 0) + 10                ageGroup = lastAgeGroup                memberGroup[lastAgeGroup] = mutableListOf()            }            memberGroup[lastAgeGroup]?.add(index)        }    }    // actual render    for ((ageGroup, memberIndexes) in memberGroup) {        stickyHeader(key = ageGroup) {            Text("< $ageGroup")        }        // you can group render into single item(...), or use individual item(...) for each        item(key = "$ageGroup-members") {            for (index in memberIndexes) {                // this will trigger pageload                val member = lazyMembers[index]                Column {                    Text("${member.name}, age=${member.age}")                }            }           }    }}

❤️ Is this article helpful?

Buy me a coffee ☕ or support my work via PayPal to keep this space 🖖 and ad-free.

Do send some 💖 to @d_luaz or share this article.

✨ By Desmond Lua

A dream boy who enjoys making apps, travelling and making youtube videos. Follow me on @d_luaz

👶 Apps I built

Travelopy - discover travel places in Malaysia, Singapore, Taiwan, Japan.