Why are highlighted items lost after scrolling in recylerview android(为什么在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;
}
}
}
});
}
无论实施哪种解决方案,结果都是一样的。滚动后,突出显示的颜色将消失。如有任何帮助,将不胜感激。
推荐答案
对现有答案添加几项内容:
- 将Adapter数据视为不可变。请勿更改适配器内部的数据。适配器需要做好...将数据从模型调整到视图(Holder)。它跟踪每个数据在定位方面所属的位置,这几乎就是它需要做的全部工作(除了自然地放大视图之外)。
- 如果您提供
Thing
的列表,其中isSelected
不是模型的一部分,而是您需要跟踪用户是否已选择它的一部分,则创建一个简单的数据类,如
data class ThingSelection(val thing: Thing, val isSelected: Boolean)
并在您的适配器中使用它,而不是只使用List<Thing>
,而使用List<ThingSelection>
。
- 请勿执行您在
onBindViewHolder
中执行的操作。您只需在那里
val item = getItem(position)
holder.bind(item)
根据您的业务规则设置其属性、背景颜色等是ViewHolder的工作。
如果您的";Item";是ThingSelection
,则viewHolder的绑定方法可以
if (item.isSelected) { ... }
将您需要的任何其他内容传递给此方法,bind(...)
是您需要的任何内容。
当用户更改项目选择时该怎么办?
您有一个单击侦听器,但不要更改数据,请让您的回调/侦听器将发生的传递给调用方。
我想象在您的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
或";层中(很可能不是片段/活动)提供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中滚动后突出显示的项目会丢失的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:为什么在Recylerview Android中滚动后突出显示的项目会丢失
基础教程推荐
- 当从同一个组件调用时,两个 IBAction 触发的顺序是什么? 2022-01-01
- 如何在 UIImageView 中异步加载图像? 2022-01-01
- Android:对话框关闭而不调用关闭 2022-01-01
- Kivy Buildozer 无法构建 apk,命令失败:./distribute.sh -m “kivy"d 2022-01-01
- android 应用程序已发布,但在 google play 中找不到 2022-01-01
- UIWebView 委托方法 shouldStartLoadWithRequest:在 WKWebView 中等效? 2022-01-01
- 如何在没有IB的情况下将2个按钮添加到右侧的UINavigationbar? 2022-01-01
- 如何在 iPhone 上显示来自 API 的 HTML 文本? 2022-01-01
- 如何让对象对 Cocos2D 中的触摸做出反应? 2022-01-01
- 在 gmail 中为 ios 应用程序检索朋友的朋友 2022-01-01