为什么在Recylerview Android中滚动后突出显示的项目会丢失 [英] Why are highlighted items lost after scrolling in recylerview android

查看:71
本文介绍了为什么在Recylerview Android中滚动后突出显示的项目会丢失的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当适配器类中的操作模式处于活动状态时,我要突出显示该项。我可以这样做,但滚动后突出显示状态消失了。我尝试了各种解决方案,但我不知道为什么会发生这种情况?

public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder>  {

   
    class MyViewHolder extends RecyclerView.ViewHolder {
 
     
     public void bind(Items viewHolder_item) {     

       
            itemView.setOnLongClickListener(new View.OnLongClickListener() {
            @Override
            public boolean onLongClick(View v) {
                isSelectMode = true;
                if (viewHolder_item.getIsSelect()){
                    
                    itemView.setBackgroundColor(Color.TRANSPARENT);
                    item.get(position).setSelect(false);
                    selectedList.remove(item.get(position));
                } else {
                    itemView.setBackgroundColor(Color.GRAY);
                    item.get(position).setSelect(true);
                    selectedList.add(item.get(position));
                }
                if (selectList.size() == 0){
                    isSelectMode = false;
                }
                return true;
            }
        });
        itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (isSelectMode){
                    if (viewHolder_item.getIsSelect()){
                        itemView.setBackgroundColor(Color.TRANSPARENT);
                        item.get(position).setSelect(false);
                        selectedList.remove(item.get(position));
                    } else {
                                                  
                       itemView.setBackgroundColor(Color.GRAY);
                       item.get(position).setSelect(true);   
                       selectedList.add(item.get(position));                      
                    }
                    if (selectList.size() == 0){
                        isSelectMode = false;
                    }
                }
            }
        });
}

无论实施哪种解决方案,结果都是一样的。滚动后,突出显示的颜色将消失。如有任何帮助,将不胜感激。

推荐答案

对现有答案添加几项内容:

  1. 将Adapter数据视为不可变。请勿更改适配器内部的数据。适配器需要做好...将数据从模型调整到视图(Holder)。它跟踪每个数据在定位方面所属的位置,这几乎就是它需要做的全部工作(除了自然地放大视图之外)。
  2. 如果您提供Thing的列表,其中isSelected不是模型的一部分,而是您需要跟踪用户是否已选择它的一部分,则创建一个简单的数据类,如
data class ThingSelection(val thing: Thing, val isSelected: Boolean)

并在您的适配器中使用它,而不是只使用List<Thing>,而使用List<ThingSelection>

  1. 请勿执行您在onBindViewHolder中执行的操作。您只需在那里
val item = getItem(position)
holder.bind(item)

根据您的业务规则设置其属性、背景颜色等是ViewHolder的工作。

如果您的";Item";是ThingSelection,则viewHolder的绑定方法可以

if (item.isSelected) { ... }

将您需要的任何其他内容传递给此方法,bind(...)是您需要的任何内容。

当用户更改项目选择时该怎么办?

您有一个单击侦听器,但不要更改数据,请让您的回调/侦听器将发生的传递给调用方。

我想象在您的viewHolder绑定方法中,您将执行如下操作:

view.setOnClickListener {
   externalListenerThatTheAdapterReceivedFromTheOutside.onThingClicked(thing, thing.isSelected)
}

此外部监听程序负责:

  1. 尽其所能(可能将其直接传递给一个ViewModel,以便它在这个新事件上工作),以确保适配器接收到新数据(现在Thing.isSelected在其中是正确的,因为用户所做的是正确的)。

  2. 确保将新的不可变列表提供给适配器,以便适配器可以计算其新数据并进行更新(提示:将ListAdapter<T, K>DiffUtil.ItemCallback<T>配合使用,将使您的工作更轻松。

更新:数据类

data class ItemWithSelection(val item: Item, val isSelected: Boolean)

然后将适配器更改为:

class YourAdapter(): ListAdapter<ItemWithSelection, YourViewHolder>(DiffUtilCallback()) {
  // You only need to override these
    
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): YourViewHolder {
        val view = LayoutInflater.from(parent.context).inflate(R.layout.your_item_layout, parent, false) // or use ViewBinding, whatever.
        return YourViewHolder(view) // you can pass more stuff if you need here, like a listener...
    }

    override fun onBindViewHolder(holder: YourViewHolder, position: Int) {
        val item = getItem(position)
        holder.bindData(item, item.isSelected) //Item is of type ItemWithSelection...
    }
}

// Somewhere in your ViewHolder...
fun bindData(item: ItemWithSelection, isSelected: Boolean) {
   // do what it needs, e.g.:
   if (isSelected) { ... } 
}


// You also need a DiffUtilCallback...
internal class DiffUtil.ItemCallback<ItemWithSelection>() {

    internal class DiffUtilCallback : DiffUtil.ItemCallback<ItemWithSelection>() {
        override fun areItemsTheSame(oldItem: ItemWithSelection, newItem: ItemWithSelection) = oldItem.item.xxx == newItem.item.xxx

        override fun areContentsTheSame(oldItem: ItemWithSelection, newItem: ItemWithSelection) = oldItem == newItem
    }

所有这些都连接好了...

在获取数据的ViewModel或";层中(很可能不是片段/活动)提供List<ItemWithSelection>...

如何构造此实际上取决于您存储所选内容的方式。

为了简单起见,假设您有两个列表:

val all: List<Item>
val selected: List<Item>
当需要为UI生成列表时,您可以(注意:我将假定您使用的是协程...您可以选择您自己风格的异步/反应式编程:

class YourViewModel: ViewModel() {

fun getYourListWithSelections() {
        viewModelScope.launch(Dispatchers.Computation) {//for e.g.
            val tempSelection = mutableListOf<ItemWithSelection>()
            all.mapTo(tempSelection) {
                    ItemWithSelection(item = it, isSelected = selection.contains(it))
                }

           // Assuming you have a MutableLiveData somewhere in this viewmodel...
           _uiState.postValue(SomeSealedClass.ListAvailable(tempSelection))
        }
}

这是从片段中自然观察到的...

class YourFragment: Fragment() {

  fun observe() {
       viewModel.uiState.observe(viewLifecycleOwner, { viewState ->
            when (viewState) {
                is SomeSealedClass.ListAvailable -> adapter.submitList(viewState.items.toMutableList())//need to pass a new list or ListAdapter won't refresh the list.
                else ... //exercise for the reader ;)
            }
        })
  }

}

这里真正缺少的就是样板的东西。

  1. ViewHolder(在View上设置click listener)如何将信息传递回ViewModel? 为您的适配器提供您选择的侦听器:
interface ItemClickListener {
  fun onItemClicked(val item: Item, val isSelected: Boolean)
}

实现它并在创建适配器时将其传递给适配器:

class YourAdapter(private val listener: ItemClickListener): ListAdapter<ItemWithSelection, YourViewHolder>(DiffUtilCallback()) {

并在您的片段中传递它:

class YourFragment: Fragment() {

private val listener = object : ItemClickListener {
   fun onItemClicked(val item: Item, val isSelected: Boolean) {
      // pass it directly, it's the VM job to deal with this and produce a new list via LiveData.
      viewModel.onItemClicked(item, isSelected)
   }
}
val adapter = YourAdapter(listener)

希望这会有帮助。

这篇关于为什么在Recylerview Android中滚动后突出显示的项目会丢失的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆