我正在尝试为RecyclerView
实现过滤器。我使用数据绑定,并且我的适配器是ListAdapter
子类,如下所示
class BookAdapter(private val clickListener: ClickHandler) :
ListAdapter<Book, BookAdapter.ViewHolder>(BooksDiffCallback()) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
return ViewHolder.from(parent)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bind(getItem(position)!!, clickListener)
}
class ViewHolder private constructor(val binding: BookItemBinding) :
RecyclerView.ViewHolder(binding.root) {
fun bind(
item: Book,
clickListener: ClickHandler
) {
binding.book = item
binding.clickListener = clickListener
binding.executePendingBindings()
}
companion object {
fun from(parent: ViewGroup): ViewHolder {
val inflater = LayoutInflater.from(parent.context)
val binding = BookItemBinding.inflate(inflater, parent, false)
return ViewHolder(binding)
}
}
}
}
class BooksDiffCallback : DiffUtil.ItemCallback<Book>() {
override fun areItemsTheSame(oldItem: Book, newItem: Book): Boolean {
return oldItem.id == newItem.id
}
override fun areContentsTheSame(oldItem: Book, newItem: Book): Boolean {
return oldItem == newItem
}
}
class ClickHandler(val clickListener: (id: String) -> Unit) {
fun onClick(item: Book) = clickListener(item.id)
}
根据文档,要添加过滤功能,我需要在适配器中实现Filterable
并定义getFilter()
方法。这就是我要坚持的地方:在getFilter()
的情况下,我根本不知道如何实现ListAdapter
。任何帮助将不胜感激。
答案 0 :(得分:9)
我遇到了类似的问题,并尝试使用与上述Maor Hadad描述的方法类似的方法来解决。它有时起作用,并且在
中引发了投放错误Filter.publishResult()
方法。所以,我用这种方法解决了。
首先创建一个变量private var unfilteredlist = listOf<BaseDataItem>()
和一个方法
fun modifyList(list : List<BaseDataItem>) {
unfilteredList = list
submitList(list)
}
fun filter(query: CharSequence?) {
val list = mutableListOf<BaseDataItem>()
// perform the data filtering
if(!query.isNullOrEmpty()) {
list.addAll(unfilteredList.filter {
it.*field1*.toLowerCase(Locale.getDefault()).contains(query.toString().toLowerCase(Locale.getDefault())) ||
it.*field2*.toLowerCase(Locale.getDefault()).contains(query.toString().toLowerCase(Locale.getDefault())) })
} else {
list.addAll(unfilteredList)
}
submitList(list)
}
在BookAdapter
类中为。 *field1*
和*field2*
(您可以添加更多字段)是您要搜索查询匹配的字段。然后,无论您在原始代码中调用adapter.submitList(List<BaseDataItem>)
到哪里,都将其替换为自定义方法adapter.modifyList(List<BaseDataItem>)
。
然后像下面这样写searchView.setOnQueryTextListener
searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
override fun onQueryTextSubmit(query: String): Boolean {
return false
}
override fun onQueryTextChange(newText: String): Boolean {
(binding.recycler.adapter as ItemAdapter).filter(newText)
return true
}
})
别忘了删除Filterable
接口及其方法,您不再需要它们
答案 1 :(得分:0)
我找不到获取列表的方法,因此我保存了对列表的引用。 代码示例:
ListAdapter: 实施可过滤:
class ItemAdapter(private val clickListener: ItemListener) :
ListAdapter<ItemAdapter.BaseDataItem, RecyclerView.ViewHolder>(ItemDiffCallBack()), Filterable {
添加变量以供参考:
var mListRef: List<BaseDataItem>? = null
var mFilteredList: List<BaseDataItem>? = null
在您首次提交列表之前,请先保存其引用
withContext(Dispatchers.Main) {
if (mListRef == null) {
mListRef = items
}
submitList(items)
}
过滤器:
override fun getFilter(): Filter {
return object : Filter() {
override fun performFiltering(charSequence: CharSequence): FilterResults {
val charString = charSequence.toString()
if (charString.isEmpty()) {
mFilteredList = mListRef
} else {
mListRef?.let {
val filteredList = arrayListOf<BaseDataItem>()
for (baseDataItem in mListRef!!) {
if (baseDataItem is BaseDataItem.DataItemWrapper) {
if (charString.toLowerCase(Locale.ENGLISH) in baseDataItem.dataItem.Name.toLowerCase(
Locale.ENGLISH
)
) {
filteredList.add(baseDataItem)
}
}
}
mFilteredList = filteredList
}
}
val filterResults = FilterResults()
filterResults.values = mFilteredList
return filterResults
}
override fun publishResults(
charSequence: CharSequence,
filterResults: FilterResults
) {
mFilteredList = filterResults.values as ArrayList<BaseDataItem>
submitList(mFilteredList)
}
}
}
如果您在片段中进行搜索,请添加以下内容:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setHasOptionsMenu(true)
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
inflater.inflate(R.menu.menu_main, menu)
val mSearchMenuItem = menu.findItem(R.id.search)
val searchView = mSearchMenuItem.actionView as SearchView
search(searchView)
super.onCreateOptionsMenu(menu, inflater)
}
private fun search(searchView: SearchView) {
searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
override fun onQueryTextSubmit(query: String): Boolean {
return false
}
override fun onQueryTextChange(newText: String): Boolean {
(binding.recycler.adapter as ItemAdapter).filter.filter(newText)
return true
}
})
}