You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何基于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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 23:50:23