求助:实现支持联系人导入与展示的多选RecyclerView
实现联系人多选RecyclerView完整步骤
1. 申请联系人权限
先在AndroidManifest.xml中声明权限:
<uses-permission android:name="android.permission.READ_CONTACTS" />
再在Activity/Fragment中动态申请权限:
// Kotlin示例 private val requestContactsPermission = registerForActivityResult(ActivityResultContracts.RequestPermission()) { granted -> if (granted) { loadContacts() } else { // 提示用户开启权限 } } // 在合适时机调用(比如onCreate) requestContactsPermission.launch(Manifest.permission.READ_CONTACTS)
2. 读取手机联系人数据
先封装联系人数据类:
data class Contact( val id: String, val name: String, val phoneNumber: String )
然后实现读取联系人的方法:
private fun loadContacts(): List<Contact> { val contacts = mutableListOf<Contact>() val contentResolver = contentResolver val projection = arrayOf( ContactsContract.Contacts._ID, ContactsContract.Contacts.DISPLAY_NAME, ContactsContract.CommonDataKinds.Phone.NUMBER ) val cursor = contentResolver.query( ContactsContract.CommonDataKinds.Phone.CONTENT_URI, projection, null, null, "${ContactsContract.Contacts.DISPLAY_NAME} ASC" ) cursor?.use { while (it.moveToNext()) { val id = it.getString(it.getColumnIndexOrThrow(ContactsContract.Contacts._ID)) val name = it.getString(it.getColumnIndexOrThrow(ContactsContract.Contacts.DISPLAY_NAME)) val phone = it.getString(it.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Phone.NUMBER)) .replace("\\s".toRegex(), "") // 去除手机号空格 contacts.add(Contact(id, name, phone)) } } return contacts }
3. 改造RecyclerView多选逻辑
基于你参考的TextView版逻辑,扩展为联系人多选:
- 用单独集合管理选中的联系人ID,不污染原始数据模型
- 点击Item切换选中状态,同步更新UI
适配器实现
先创建Item布局item_contact.xml:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:padding="16dp" android:gravity="center_vertical"> <CheckBox android:id="@+id/cb_select" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginEnd="16dp"/> <LinearLayout android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:orientation="vertical"> <TextView android:id="@+id/tv_name" android:layout_width="match_parent" android:layout_height="wrap_content" android:textSize="16sp" android:textStyle="bold"/> <TextView android:id="@+id/tv_phone" android:layout_width="match_parent" android:layout_height="wrap_content" android:textSize="14sp" android:textColor="@android:color/darker_gray" android:layout_marginTop="4dp"/> </LinearLayout> </LinearLayout>
然后编写适配器:
class ContactMultiSelectAdapter( private val contacts: List<Contact> ) : RecyclerView.Adapter<ContactMultiSelectAdapter.ContactViewHolder>() { // 存储选中的联系人ID private val selectedContactIds = mutableSetOf<String>() inner class ContactViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { val cbSelect: CheckBox = itemView.findViewById(R.id.cb_select) val tvName: TextView = itemView.findViewById(R.id.tv_name) val tvPhone: TextView = itemView.findViewById(R.id.tv_phone) } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ContactViewHolder { val view = LayoutInflater.from(parent.context).inflate(R.layout.item_contact, parent, false) return ContactViewHolder(view) } override fun onBindViewHolder(holder: ContactViewHolder, position: Int) { val contact = contacts[position] holder.tvName.text = contact.name holder.tvPhone.text = contact.phoneNumber // 设置选中状态 holder.cbSelect.isChecked = selectedContactIds.contains(contact.id) // Item点击事件 holder.itemView.setOnClickListener { if (selectedContactIds.contains(contact.id)) { selectedContactIds.remove(contact.id) } else { selectedContactIds.add(contact.id) } notifyItemChanged(position) } // CheckBox与Item点击联动 holder.cbSelect.setOnClickListener { holder.itemView.performClick() } } override fun getItemCount(): Int = contacts.size // 获取选中的联系人列表 fun getSelectedContacts(): List<Contact> { return contacts.filter { selectedContactIds.contains(it.id) } } // 全选/取消全选(可选) fun toggleAllSelect() { if (selectedContactIds.size == contacts.size) { selectedContactIds.clear() } else { selectedContactIds.addAll(contacts.map { it.id }) } notifyDataSetChanged() } }
4. 初始化RecyclerView
在Activity/Fragment中绑定数据:
private fun setupRecyclerView(contacts: List<Contact>) { val recyclerView = findViewById<RecyclerView>(R.id.rv_contacts) recyclerView.layoutManager = LinearLayoutManager(this) val adapter = ContactMultiSelectAdapter(contacts) recyclerView.adapter = adapter // 示例:点击按钮获取选中联系人 findViewById<Button>(R.id.btn_get_selected).setOnClickListener { val selected = adapter.getSelectedContacts() selected.forEach { Log.d("Selected", "${it.name} - ${it.phoneNumber}") } } }
5. 可选优化
- 长按Item进入批量选择模式(仿系统联系人)
- 选中时修改Item背景色,增强视觉反馈
- 过滤无手机号的联系人
- 分页加载大量联系人避免卡顿
内容的提问来源于stack exchange,提问作者Optix
相关产品推荐
相关产品推荐

