为什么在Recylerview Android中滚动后突出显示的项目会丢失

本教程将介绍为什么在Recylerview Android中滚动后突出显示的项目会丢失的处理方法,这篇教程是从别的地方看到的,然后加了一些国外程序员的疑问与解答,希望能对你有所帮助,好了,下面开始学习吧。

为什么在Recylerview Android中滚动后突出显示的项目会丢失 教程 第1张

问题描述

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

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;
  }
 }
}
  });
}

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

推荐答案

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

    将Adapter数据视为。请勿更改适配器内部的数据。适配器需要做好...将数据从模型调整到视图(Holder)。它跟踪每个数据在定位方面所属的位置,这几乎就是它需要做的全部工作(除了自然地放大视图之外)。

    如果您提供Thing的列表,其中isSelected不是模型的一部分,而是您需要跟踪数据,请让您的回调/侦听器将传递给调用方。

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

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

    此外部监听程序负责:

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

      确保将新的不可变列表提供给适配器,以便适配器可以计算其新数据并进行更新(提示:将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或&quot;层中(很可能)提供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 ;)
    }
      })
      }
    
    }
    

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

      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中滚动后突出显示的项目会丢失的教程就到这里就结束了,希望趣模板源码网找到的这篇技术文章能帮助到大家,更多技术教程可以在站内搜索。