Compose 一个联系人索引列表实现

一、前言

该功能是一个左侧为字符索引列表,右侧为联系人列表的实现,点击左侧字符索引可以自动滑动到对应联系人条目。该功能代码实现绝大多数有通义灵码完成。实现效果如下:
在这里插入图片描述

关键代码

data class Contact(val name: String)

class ContactsPage {
    val contacts = listOf(
        Contact("Alice"),
        Contact("Bob"),
        Contact("Charlie"),
        Contact("David"),
        Contact("Eve"),
        Contact("Frank"),
        Contact("Grace"),
        Contact("Heidi"),
        Contact("Ivan"),
        Contact("John"),
        Contact("Karen"),
        Contact("Larry"),
        Contact("Mary"),
        Contact("Nancy"),
        Contact("Olivia"),
        Contact("Paul"),
        Contact("Quincy"),
        Contact("Rachel"),
        Contact("Steve"),
        Contact("Tom"),
        Contact("Ursula"),
        Contact("Victor"),
        Contact("Wendy"),
        Contact("Xavier"),
        Contact("Yolanda"),
        Contact("Zoe")
    )

    fun alphabetIndexer(contact: Contact) = contact.name.first().toString().uppercase()

    @Composable
    fun IndexedContactsList(contacts: List<Contact>) {
        val indexer = { contact: Contact -> alphabetIndexer(contact) }
        val sections = contacts.groupBy(indexer)
        val entries = sections.entries.toList()

        // 记录每个字母索引的位置
        val letterPositions = remember { mutableMapOf<String, Int>() }
        val listState = remember { LazyListState() }

        // 计算每个字母索引的位置
        var currentLetter = ""
        for ((position, contact) in contacts.withIndex()) {
            val letter = indexer(contact)
            if (letter != currentLetter) {
                letterPositions[letter] = position
                currentLetter = letter
            }
        }
        val coroutineScope = rememberCoroutineScope()
        Row(
            modifier = Modifier.fillMaxSize()
        ) {
            // 右侧字母索引列表
            LazyColumn(
                modifier = Modifier
                    .weight(0.2f) // 设置宽度比例
                    .fillMaxHeight()
                    .padding(8.dp)
            ) {
                itemsIndexed(entries) { index, entry ->
                    Text(
                        text = entry.key,
                        modifier = Modifier
                            .fillMaxWidth()
                            .clickable {
                                /* Handle click */
                                // 点击字母索引时滚动到对应位置
                                coroutineScope.launch {
                                    listState.animateScrollToItem(letterPositions[entry.key] ?: 0)
                                }
                            }
                            .padding(vertical = 8.dp),
                        style = MaterialTheme.typography.subtitle1,
                        color = Color.Gray
                    )
                }
            }

            // 左侧联系人列表
            LazyColumn(
                state = listState,
                modifier = Modifier
                    .weight(0.8f) // 设置宽度比例
                    .fillMaxHeight()
                    .padding(8.dp)
            ) {
                itemsIndexed(contacts) { index, contact ->
                    val letter = indexer(contact)
                    if (index == 0 || indexer(contacts[index - 1]) != letter) {
                        Text(
                            text = letter,
                            modifier = Modifier.padding(
                                start = 16.dp,
                                top = 8.dp,
                                end = 16.dp,
                                bottom = 4.dp
                            ),
                            style = MaterialTheme.typography.subtitle1,
                            color = Color.Gray
                        )
                    }
                    Text(
                        text = contact.name,
                        modifier = Modifier
                            .fillMaxWidth()
                            .clickable { /* Handle click */ }
                            .padding(horizontal = 16.dp, vertical = 8.dp),
                        style = MaterialTheme.typography.body1
                    )
                }
            }
        }
    }

    @Preview(showBackground = true)
    @Composable
    fun PreviewIndexedContactsList() {
        MaterialTheme {
            IndexedContactsList(contacts)
        }
    }
}
在 Jetpack Compose 中,如果你想使用 `LazyColumn` 创建一个类似宫格式的网格列表,可以结合 `Grid` 或者 `Row` 控件以及 `RecyclerGridState`。下面是一个基本的示例,展示如何将项目分组到网格格子中: ```kotlin import androidx.compose.foundation.layout.Arrangement.RowMajor import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Grid import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.material.Button import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp @Composable fun GridListWithColumns(groups: List<List<String>>) { LazyColumn { items(groups) { group -> Grid( columns = 3, spacing = 8.dp, contentPadding = PaddingValues(vertical = 8.dp), modifier = Modifier.fillMaxWidth(), arrangement = Arrangement.RowMajor ) { group.forEachIndexed { index, item -> if (index % 3 == 2) { Spacer(modifier = Modifier.size(0.dp)) } else { Button(onClick = { /* Your click action here */ }) { Text(text = item, style = MaterialTheme.typography.body2) } } } } } } } // 使用时传递数据 val data = listOf( listOf("Group 1 Item 1", "Group 1 Item 2", "Group 1 Item 3"), listOf("Group 2 Item 1", "Group 2 Item 2", "Group 2 Item 3"), // 更多数据... ) GridListWithColumns(data) ``` 这个例子中,我们创建了一个懒加载列,每行显示三个元素,当到达网格的最后一行时,会插入一个空隙。每个项目的点击动作可以根据实际需求来实现
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值