如何基于AppListAdapter实现SearchView对RecyclerView的内容过滤?
RecyclerView应用列表搜索过滤实现方案
第一步:修改适配器类,添加过滤能力
原适配器直接使用appList存储数据,过滤后无法恢复原始列表,需要调整结构保留原始数据集,并新增过滤方法:
class AppListAdapter(private val context: Context, initialChecked: ArrayList<String> = arrayListOf()) : RecyclerView.Adapter<AppListAdapter.AppViewHolder>() { // 用于展示的过滤后列表 public val appList = arrayListOf<ApplicationInfo>() // 存储全量符合条件的应用(用于过滤时的数据源) private val originalAppList = arrayListOf<ApplicationInfo>() private val checkedAppList = arrayListOf<Boolean>() private val packageManager: PackageManager = context.packageManager // 保留初始选中数据,用于过滤时恢复选中状态 private val initialCheckedSet = initialChecked.toSet() init { // 先筛选出所有非系统、非当前应用的程序,存入原始列表 context.packageManager.getInstalledApplications(PackageManager.GET_META_DATA) .sortedBy { it.loadLabel(packageManager).toString() } .forEach { info -> if (info.packageName != context.packageName && (info.flags and ApplicationInfo.FLAG_SYSTEM) == 0) { originalAppList.add(info) } } // 初始化展示列表和选中状态 refreshListWithData(originalAppList) } // 统一更新列表和选中状态的工具方法 private fun refreshListWithData(dataList: List<ApplicationInfo>) { appList.clear() checkedAppList.clear() appList.addAll(dataList) dataList.forEach { info -> checkedAppList.add(initialCheckedSet.contains(info.packageName)) } notifyDataSetChanged() } // 对外暴露的过滤方法 fun filter(query: String?) { val filterText = query?.trim() ?: "" if (filterText.isEmpty()) { // 空输入时显示全部应用 refreshListWithData(originalAppList) } else { // 根据应用名称或包名过滤(忽略大小写) val filteredList = originalAppList.filter { info -> val appName = info.loadLabel(packageManager).toString().lowercase() val pkgName = info.packageName.lowercase() appName.contains(filterText.lowercase()) || pkgName.contains(filterText.lowercase()) } refreshListWithData(filteredList) } } inner class AppViewHolder(private val item: ItemAppBinding) : RecyclerView.ViewHolder(item.root) { fun bind(data: ApplicationInfo, position: Int) { item.txApp.text = data.loadLabel(packageManager) item.imgIcon.setImageDrawable(data.loadIcon(packageManager)) item.cbApp.isChecked = checkedAppList[position] item.cbApp.setOnCheckedChangeListener { _, checked -> checkedAppList[position] = checked } } } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AppViewHolder { return AppViewHolder(ItemAppBinding.inflate(LayoutInflater.from(context), parent, false)) } override fun onBindViewHolder(holder: AppViewHolder, position: Int) { holder.bind(appList[position], position) } override fun getItemCount(): Int { return appList.size } }
第二步:在MainActivity中调用过滤方法
在SearchView的监听回调里直接调用适配器的filter方法即可,两个回调的逻辑一致,仅onQueryTextSubmit多了清除焦点的操作:
// 假设已初始化适配器并绑定到RecyclerView: // val appAdapter = AppListAdapter(this) // binding.recyclerView.adapter = appAdapter binding.searchView2.setOnQueryTextListener(object : SearchView.OnQueryTextListener{ override fun onQueryTextSubmit(query: String?): Boolean { binding.searchView2.clearFocus() appAdapter.filter(query) return true } override fun onQueryTextChange(newText: String?): Boolean { appAdapter.filter(newText) return true } })
补充说明
- 过滤逻辑支持应用名称和包名的模糊匹配,且忽略大小写,适配用户不同的输入习惯
- 输入为空时自动恢复显示全部应用,选中状态与初始设置保持一致
- 用
Set存储初始选中的包名,提升判断效率
内容的提问来源于stack exchange,提问作者rakadiptya
相关产品推荐
相关产品推荐

