当我在 recyclerview 列表中搜索时,它会将项目删除到原始 recyclerview 列表中
When I search in the list of the recyclerview it removes items into original recyclerview list
我有下一个 recyclerview
适配器,它实现了 Filterable
class 来尝试在我的 productList
中搜索并更新 recyclerview。
class ProductsAdapterV2(
private val itemClickListener: OnProductClickListener
) : RecyclerView.Adapter<BaseViewHolder<*>>(), Filterable {
private var productsList = listOf<Product>()
private var productsListBackup = listOf<Product>()
interface OnProductClickListener {
//Método para gestionar el OnClick de los items del recyclerview
fun onProductClick(product: Product)
//Método para gestionar el click largo cuando se toca el item por unos segundos..
fun onProductLongClick(product: Product, position: Int)
}
fun setProductList(productsList: List<Product>) {
this.productsList = productsList
this.productsListBackup = productsList
notifyDataSetChanged()
}
fun getProductList():List<Product>{
return this.productsList
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseViewHolder<*> {
val itemBinding = ProductsListBinding.inflate(LayoutInflater.from(parent.context), parent, false)
val holder = MainViewHolder (itemBinding)
holder.itemView.setOnClickListener {
val position = holder.adapterPosition.takeIf { it != DiffUtil.DiffResult.NO_POSITION }
?: return@setOnClickListener
itemClickListener.onProductClick(productsList[position])
}
holder.itemView.setOnLongClickListener {
val position = holder.adapterPosition.takeIf { it != NO_POSITION }
?: return@setOnLongClickListener true
itemClickListener.onProductLongClick(productsList[position], position)
return@setOnLongClickListener true
}
return holder
}
override fun onBindViewHolder(holder: BaseViewHolder<*>, position: Int) {
when (holder) {
is MainViewHolder -> holder.bind(productsList[position])
}
}
override fun getItemCount(): Int = productsList.size
private inner class MainViewHolder (val binding: ProductsListBinding) : BaseViewHolder<Product>(binding.root) {
override fun bind(item: Product) {
val description = if (item.description.isNotEmpty()) item.description else "Sin descripción."
val barcode = if (item.barcode.isNotEmpty()) item.barcode else "Sin código."
binding.txtName.text=item.name
binding.txtDescription.text=description
binding.txtBarcode.text=barcode
binding.txtQty.text = "Cantidad: ${item.qty}"
binding.txtPrice.text = "S/${item.price}"
//Si el image_bitmap no es nulo:
item.image_bitmap?.let { binding.productImage.setImageBitmap(item.image_bitmap!!) }
}
}
//Filterable methods to search
override fun getFilter(): Filter {
return object : Filter() {
override fun performFiltering(charSequence: CharSequence?): Filter.FilterResults {
val queryString = charSequence?.toString()?.lowercase()
val filterResults = Filter.FilterResults()
filterResults.values = if (queryString==null || queryString.isEmpty())
productsList
else
productsList.filter {
it.name.lowercase().contains(queryString) ||
it.barcode.lowercase().contains(queryString) ||
it.description.lowercase().contains(queryString)
}
return filterResults
}
override fun publishResults(charSequence: CharSequence?, filterResults: Filter.FilterResults) {
productsList = filterResults.values as List<Product>
notifyDataSetChanged()
}
}
}
}
要搜索,我正在使用 SearchView
:
private fun setupSearchView(){
binding.searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener{
override fun onQueryTextSubmit(query: String?): Boolean {
productsRecyclerViewAdapterV2.filter.filter(query)
return false
}
override fun onQueryTextChange(newText: String?): Boolean {
productsRecyclerViewAdapterV2.filter.filter(newText!!)
return false
}
})
}
然而,搜索任务在开始时运行良好,但在搜索完某些内容后,整个 productList
已更新并且现在的数据比以前少,我可以在输入内容时看到这种罕见的行为然后我删除一些单词 --The list has now less data--
示例:
初始列表:
正在搜索内容:
现在我删除 searchView
:
中的整个文本
我们可以看到recyclerview没有更新原始数据,现在只有之前搜索的项目。
我想改进 recyclerview 适配器的功能 getFilter()
因为我认为那里有问题或者可能在方法内部 publishResults()
.
任何解决此问题的想法,我将不胜感激。
提前致谢。
您已经有一个备份列表,这很好,但您需要使用该备份列表作为完整项目列表的来源,否则您的过滤器将继续过滤其之前的输出而不是原始的完整列表项目列表。
另外,小费。使用 String?.orEmpty()
可以避免比您必须更多地处理可为 null 的值。
override fun performFiltering(charSequence: CharSequence?): Filter.FilterResults {
val queryString = charSequence?.toString().orEmpty().lowercase()
return Filter.FilterResults().apply {
values = when {
queryString.isEmpty() -> productsListBackup
else -> productsListBackup.filter {
it.name.lowercase().contains(queryString) ||
it.barcode.lowercase().contains(queryString) ||
it.description.lowercase().contains(queryString)
}
}
}
旁注:在 Kotlin 中,您不应创建 get...()
和 set...()
函数。您已经拥有属性,因此 getters 和 setters 是隐含的。如果您需要做任何复杂的事情,您可以定义自定义 getter 或 setter 行为。因此,在您的情况下,您可以删除 getProductList()
和 setProductList()
并将现有的 属性 更新为 public 并且看起来像:
var productsList = listOf<Product>()
set(value) {
field = value
productsListBackup = productsList
notifyDataSetChanged()
}
我有下一个 recyclerview
适配器,它实现了 Filterable
class 来尝试在我的 productList
中搜索并更新 recyclerview。
class ProductsAdapterV2(
private val itemClickListener: OnProductClickListener
) : RecyclerView.Adapter<BaseViewHolder<*>>(), Filterable {
private var productsList = listOf<Product>()
private var productsListBackup = listOf<Product>()
interface OnProductClickListener {
//Método para gestionar el OnClick de los items del recyclerview
fun onProductClick(product: Product)
//Método para gestionar el click largo cuando se toca el item por unos segundos..
fun onProductLongClick(product: Product, position: Int)
}
fun setProductList(productsList: List<Product>) {
this.productsList = productsList
this.productsListBackup = productsList
notifyDataSetChanged()
}
fun getProductList():List<Product>{
return this.productsList
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseViewHolder<*> {
val itemBinding = ProductsListBinding.inflate(LayoutInflater.from(parent.context), parent, false)
val holder = MainViewHolder (itemBinding)
holder.itemView.setOnClickListener {
val position = holder.adapterPosition.takeIf { it != DiffUtil.DiffResult.NO_POSITION }
?: return@setOnClickListener
itemClickListener.onProductClick(productsList[position])
}
holder.itemView.setOnLongClickListener {
val position = holder.adapterPosition.takeIf { it != NO_POSITION }
?: return@setOnLongClickListener true
itemClickListener.onProductLongClick(productsList[position], position)
return@setOnLongClickListener true
}
return holder
}
override fun onBindViewHolder(holder: BaseViewHolder<*>, position: Int) {
when (holder) {
is MainViewHolder -> holder.bind(productsList[position])
}
}
override fun getItemCount(): Int = productsList.size
private inner class MainViewHolder (val binding: ProductsListBinding) : BaseViewHolder<Product>(binding.root) {
override fun bind(item: Product) {
val description = if (item.description.isNotEmpty()) item.description else "Sin descripción."
val barcode = if (item.barcode.isNotEmpty()) item.barcode else "Sin código."
binding.txtName.text=item.name
binding.txtDescription.text=description
binding.txtBarcode.text=barcode
binding.txtQty.text = "Cantidad: ${item.qty}"
binding.txtPrice.text = "S/${item.price}"
//Si el image_bitmap no es nulo:
item.image_bitmap?.let { binding.productImage.setImageBitmap(item.image_bitmap!!) }
}
}
//Filterable methods to search
override fun getFilter(): Filter {
return object : Filter() {
override fun performFiltering(charSequence: CharSequence?): Filter.FilterResults {
val queryString = charSequence?.toString()?.lowercase()
val filterResults = Filter.FilterResults()
filterResults.values = if (queryString==null || queryString.isEmpty())
productsList
else
productsList.filter {
it.name.lowercase().contains(queryString) ||
it.barcode.lowercase().contains(queryString) ||
it.description.lowercase().contains(queryString)
}
return filterResults
}
override fun publishResults(charSequence: CharSequence?, filterResults: Filter.FilterResults) {
productsList = filterResults.values as List<Product>
notifyDataSetChanged()
}
}
}
}
要搜索,我正在使用 SearchView
:
private fun setupSearchView(){
binding.searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener{
override fun onQueryTextSubmit(query: String?): Boolean {
productsRecyclerViewAdapterV2.filter.filter(query)
return false
}
override fun onQueryTextChange(newText: String?): Boolean {
productsRecyclerViewAdapterV2.filter.filter(newText!!)
return false
}
})
}
然而,搜索任务在开始时运行良好,但在搜索完某些内容后,整个 productList
已更新并且现在的数据比以前少,我可以在输入内容时看到这种罕见的行为然后我删除一些单词 --The list has now less data--
示例:
初始列表:
正在搜索内容:
现在我删除 searchView
:
我们可以看到recyclerview没有更新原始数据,现在只有之前搜索的项目。
我想改进 recyclerview 适配器的功能 getFilter()
因为我认为那里有问题或者可能在方法内部 publishResults()
.
任何解决此问题的想法,我将不胜感激。 提前致谢。
您已经有一个备份列表,这很好,但您需要使用该备份列表作为完整项目列表的来源,否则您的过滤器将继续过滤其之前的输出而不是原始的完整列表项目列表。
另外,小费。使用 String?.orEmpty()
可以避免比您必须更多地处理可为 null 的值。
override fun performFiltering(charSequence: CharSequence?): Filter.FilterResults {
val queryString = charSequence?.toString().orEmpty().lowercase()
return Filter.FilterResults().apply {
values = when {
queryString.isEmpty() -> productsListBackup
else -> productsListBackup.filter {
it.name.lowercase().contains(queryString) ||
it.barcode.lowercase().contains(queryString) ||
it.description.lowercase().contains(queryString)
}
}
}
旁注:在 Kotlin 中,您不应创建 get...()
和 set...()
函数。您已经拥有属性,因此 getters 和 setters 是隐含的。如果您需要做任何复杂的事情,您可以定义自定义 getter 或 setter 行为。因此,在您的情况下,您可以删除 getProductList()
和 setProductList()
并将现有的 属性 更新为 public 并且看起来像:
var productsList = listOf<Product>()
set(value) {
field = value
productsListBackup = productsList
notifyDataSetChanged()
}