【问题标题】:How to search a diffutil filter out results from existing list如何从现有列表中搜索 diffutil 过滤掉结果
【发布时间】:2020-12-09 15:19:41
【问题描述】:

我在我的 RecyclerView 中使用 DiffUtil 来使用 Room 组件显示来自数据库的列表。我想在 Appbar 中添加一个搜索功能,它会在用户输入时过滤掉列表中的现有项目。

我的应用目前在操作栏中有一个搜索图标,当您单击搜索图标时,它将在整个应用栏展开并允许用户搜索数据库并返回一个新列表。该方法涉及每次查询数据库。

搜索菜单,这是设置搜索小部件参数的地方。

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <item android:id="@+id/my_search"
        android:title="Search"
        android:icon="@drawable/ic_search"
        app:showAsAction="collapseActionView|ifRoom"
        app:actionViewClass="androidx.appcompat.widget.SearchView" />
</menu>

RecyclerViewFragment

    override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
        super.onCreateOptionsMenu(menu, inflater)
        inflater.inflate(R.menu.recycler_view_menu, menu)

        val searchItem = menu.findItem(R.id.my_search)
        val searchView: SearchView = searchItem.actionView as SearchView
        searchView.imeOptions = EditorInfo.IME_ACTION_DONE   
        searchView.setIconifiedByDefault(false)
        searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
            override fun onQueryTextSubmit(query: String): Boolean {
                // This approach queries my database for a new list. 
                viewModel.searchTopic("%$query%")
                submitList()
                return false
            }

            override fun onQueryTextChange(newText: String): Boolean {
                // I would like to use the onTextChange() to filter out results from the list instead of querying a new list from the database. 
                return true
            }

        })
    }


    private fun submitList() {
        viewModel.listDevTopics.observe(viewLifecycleOwner, Observer {
            it?.let {
                rvAdapter.submitList(it)
            }
        })
    }

我的 RecyclerViewAdapter

class RecyclerViewAdapter() : androidx.recyclerview.widget.ListAdapter<Dev,
        RecyclerViewAdapter.ItemViewHolder>(MyDiffCallback()) {


    lateinit var searchList: List<Dev>

    class MyDiffCallback : DiffUtil.ItemCallback<Dev>() {
        
        override fun areItemsTheSame(oldItem: Dev, newItem: Dev): Boolean {
            return oldItem.topic == newItem.topic
        }

        override fun areContentsTheSame(oldItem: Dev, newItem: Dev): Boolean {
            return oldItem == newItem
        }
    }


    class ItemViewHolder(private val view: View) :  RecyclerView.ViewHolder(view) {
         ...
    }


    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemViewHolder {
        ...
    }

    override fun onBindViewHolder(holder: ItemViewHolder, position: Int) {
        ...
    }

我想避免每次都查询数据库以获取搜索结果,我想使用 onQueryTextChange 以便它遍历现有列表并在用户输入查询时更新列表。

【问题讨论】:

    标签: kotlin android-search android-diffutils


    【解决方案1】:

    只需实现 Filterable 并覆盖 getFilter 方法

    并制作您的过滤器对象,然后在 getFilter 方法中返回此对象

    class JobOrderAdapter(val clickListener: JobOrderListener) : ListAdapter<CJO,
        ViewHolder>(JobOrderDiffCallback()), Filterable {
    
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder =
        ViewHolder.from(parent)
    
    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        val item = getItem(position)
        holder.bind(item, clickListener)
    }
    
    private var list = listOf<CJO>()
    
    fun setData(list: List<CJO>){
        this.list = list
        submitList(list)
    }
    
    override fun getFilter(): Filter = customFilter
    
    private val customFilter = object : Filter() {
        override fun performFiltering(constraint: CharSequence?): FilterResults {
            val filteredList = mutableListOf<CJO>()
            if (constraint == null || constraint.isEmpty()) {
                filteredList.addAll(list)
            } else {
                val filterPattern = constraint.toString().toLowerCase().trim()
    
                for (item in list) {
    // here i am searching at custom obj by managerName
                    if (item.managerName.toLowerCase().contains(filterPattern)) {
                        filteredList.add(item)
                    }
                }
            }
            val results = FilterResults()
            results.values = filteredList
            return results
        }
    
        override fun publishResults(constraint: CharSequence?, filterResults: FilterResults?) {
            submitList(filterResults?.values as MutableList<CJO>?)
        }
    }}
    

    然后从您的 Fragmnet 或活动中调用 adapter.filter.filter(yourQueryText)

        override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
        inflater.inflate(R.menu.home_menu, menu)
        val searchByContract = menu.findItem(R.id.search_by_name)
        val searchContractView = searchByContract.actionView as SearchView
    
        searchContractView.queryHint = "البحث باسم مدير البيع"
        searchContractView.inputType = InputType.TYPE_CLASS_TEXT
    
        searchContractView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
            override fun onQueryTextSubmit(query: String): Boolean {
                return false
            }
    
            override fun onQueryTextChange(newText: String?): Boolean {
                adapter.filter.filter(newText)
                return false
            }
        })
    
        super.onCreateOptionsMenu(menu, inflater)
    }
    

    【讨论】:

      猜你喜欢
      • 2020-04-07
      • 1970-01-01
      • 1970-01-01
      • 2019-07-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多