Android RecyclerView适配器notifyDataSetChanged停止高级动画
我正在基于RecyclerView构建一个组件,允许用户通过拖放来重新排序项目。 一旦我在DragListener侧,我需要它在适配器中的位置,以便执行正确的移动,但我只能访问视图。 下面是我在适配器视图绑定中所做的工作:Android RecyclerView适配器notifyDataSetChanged停止高级动画,android,adapter,android-recyclerview,Android,Adapter,Android Recyclerview,我正在基于RecyclerView构建一个组件,允许用户通过拖放来重新排序项目。 一旦我在DragListener侧,我需要它在适配器中的位置,以便执行正确的移动,但我只能访问视图。 下面是我在适配器视图绑定中所做的工作: @Override public void onBindViewHolder(ViewHolder viewHolder, int position) { Track track = mArray.get(position); viewHolder.itemV
@Override
public void onBindViewHolder(ViewHolder viewHolder, int position) {
Track track = mArray.get(position);
viewHolder.itemView.setTag(R.string.TAG_ITEM_POSITION, position);
}
你觉得对吗?
因为如果我像这样移动一个项目:
public void move(int from, int to){
Track track = mArray.remove(from);
mArray.add(to, track);
notifyItemMoved(from, to);
}
然后,位置标记不再正确,如果我通知DataSetChanged(),我将丢失精美的动画。
有什么建议吗?没有,这是错误的。首先,在该方法返回后,不能引用传递给onBindViewHolder的位置。当视图位置发生变化(由于项目移动等原因)时,RecyclerView不会重新绑定视图 相反,您可以使用
ViewHolder#getPosition()
,它将返回更新后的位置
如果你解决了这个问题,你的移动代码应该可以工作,并提供很好的动画效果
调用notifyDataSetChanged将阻止预测性动画,因此请尽可能避免它。有关详细信息,请参阅
编辑(从注释):要从外部获取位置,请从recyclerview获取子视图持有者,然后从vh获取位置。有关详细信息,请参见RecyclerView api有一种方法可以仅使用
notifyDataSetChanged()
GridLayoutManager
,使用重写的supportsPredictiveItemAnimations()
方法返回true
mAdapter.setHasStableIds(true)
getItemId()
方法。它应该返回真正唯一的值,而不是位置的直接函数。类似于mItems.get(position.hashCode()
notifyDataSetChanged()
1)添加、删除和移动项目的漂亮动画,您将使用notifyItemInserted(position)代码>或notifyItemRemoved(位置)代码>而不是动画的notifyDataSetChanged()
。
2) 您可以手动修复您的问题-使用
public void move(int from, int to){
Track track = mArray.remove(from);
mArray.add(to, track);
notifyItemMoved(from, to);
ViewHolder fromHolder = (ViewHolder) mRecyclerView.findViewHolderForPosition(from);
ViewHolder toHolder = (ViewHolder) mRecyclerView.findViewHolderForPosition(to);
Tag fromTag = fromHolder.itemView.getTag();
fromHolder.itemView.setTag(toHolder.itemView.getTag());
toHolder.itemView.setTag(fromTag);
}
您应该将方法移动到OnCreateViewHolder
,然后notifyItemRemoved(index)
正常工作。我可以通过将其添加到列表项的外部元素来维护触摸动画
<View
android:foreground="?android:attr/selectableItemBackground"
...>
我使用'notifyItemChanged(int位置);'而不是“notifyDataSetChanged();”
我的适配器完美地显示了精美的动画,没有任何延迟
编辑:我从onBindViewHolder的位置获得了位置。如上所述,您可以在适配器上使用notifyDataSetChanged
时进行动画,尽管您需要特别使用稳定ID。如果项目id是字符串,则可以为每个字符串id生成一个长id,并将其保存在映射中。例如:
class StringToLongIdMap {
private var stringToLongMap = HashMap<String, Long>()
private var longId: Long = 0
fun getLongId(stringId: String): Long {
if (!stringToLongMap.containsKey(stringId)) {
stringToLongMap[stringId] = longId++
}
return stringToLongMap[stringId] ?: -1
}
}
另一个有用的考虑事项,如果您使用KOTLIN数据类作为适配器中的项,并且没有ID,则可以使用数据类本身的哈希代码作为稳定的ID(如果您确信项目属性组合在数据集中是唯一的):
好的,谢谢你的回答=)但是现在从Adpeter外部(例如我的dragListener)检索位置的最佳方法是什么?从recyclerview获取子视图支架,然后从vh获取位置。详细信息请参见RecyclerView api GetPosition()已被弃用,因为它太不明确。在这种情况下,您需要使用getLayoutPosition(),但mAdapter.notifyItemMoved(viewHolder.getAdapterPosition(),target.getAdapterPosition())代码>糟透了。我看到物品被移动了集合。交换(………)
但是当我点击它们时,它们是旧的(所以只有物品的标题被更改了)。你帮我省了很多麻烦,tyvm。顺便说一句,这应该是可以接受的答案,而不是上面的答案。我忘了说,如果您使用DB为适配器提供类似于第3部分主键的内容将解决您的问题。嗨,我不明白您需要什么,请使用“mItems.get(position).hashCode()”返回long我需要返回一个对象..,您能告诉我吗?如何返回对象?thxIt是为你的返回long的方法设计的。no 3是让我的应用程序开心的东西!!:)它无法控制自己的情绪。更改项目(位置)
private var stringToLongIdMap = StringToLongIdMap()
override fun getItemId(position: Int): Long {
val item = items[position]
return stringToLongIdMap.getLongId(item.id)
}
override fun getItemId(position: Int): Long = items[position].hashCode().toLong()