kotlin - 如何从现有列表中搜索 diffutil 过滤掉结果
问题描述
我在我的 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 以便它遍历现有列表并在用户输入查询时更新列表。
解决方案
只需实现 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)
}
推荐阅读
- c# - C# .Replace() method does not work correctly with Arabic language
- r - R中ols命令(rms包)的linearHypothesis等价物
- c++ - boost::stacktrace::frame::name() 挂起
- c# - 在 C# 中逐个单元格或一次全部读取 Excel 工作表是否更好?
- android - 在颤动中显示全屏加载小部件
- mongodb - 带有多字段计数的groupby的mongodb
- python - 我需要打印具有不同字段的不同字典,ValueError: dict contains fields not in fieldnames:
- linux - Bash replacing part of output with a string
- matlab - 如何在 Windows 7 上安装 Veins 5a1?并将其与 Matlab 连接
- linux - 如何创建一个正常运行的程序?因为我的程序永远运行并且不会停止