我正在构建一个基于RecyclerView的组件,允许用户通过拖放重新排序项目。 一旦我在DragListener端,我需要它在适配器中的位置,以便执行正确的移动,但我只能访问视图。 所以这就是我在适配器视图绑定中所做的事情:
@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);
}
然后位置标记不再正确,如果我notifyDataSetChanged(),我会失去花哨的动画。 有什么建议吗?
答案 0 :(得分:105)
有一种方法可以使用notifyDataSetChanged()
您需要使用覆盖GridLayoutManager
方法制作自己的supportsPredictiveItemAnimations()
{/ 1}};
您需要true
我发现棘手的部分是您需要覆盖适配器的mAdapter.setHasStableIds(true)
方法。它应该返回真正唯一的值,而不是getItemId()
的直接函数。像position
在我的情况下工作得很好 - 仅使用mItems.get(position).hashCode()
答案 1 :(得分:5)
不,这是错的。首先,不能引用该方法返回后传递给onBindViewHolder的位置。当物品的位置发生变化时(由于物品移动等),RecyclerView不会重新绑定视图。
相反,您可以使用ViewHolder#getPosition()
来返回更新的位置。
如果你解决了这个问题,那么你的移动代码应该可以正常工作。提供精彩的动画。
调用notifyDataSetChanged
会阻止预测动画,因此请尽可能避免使用。有关详细信息,请参阅documentation。
编辑(来自评论):从外部获取位置,从recyclerview获取子视图持有者,然后从vh获取位置。有关详细信息,请参阅RecyclerView api
答案 2 :(得分:3)
1)您将notifyItemInserted(position);
或notifyItemRemoved(position);
代替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);
}
答案 3 :(得分:0)
您应该将方法移至print("{} hours, {} minutes, {} seconds".format(h, m, s), end = "\r")
,然后OnCreateViewHolder
正常工作。
答案 4 :(得分:0)
通过将触摸动画添加到列表项的外部元素中,我可以保持触摸动画
<View
android:foreground="?android:attr/selectableItemBackground"
...>
答案 5 :(得分:0)
我使用'notifyItemChanged(int position);'修复了它而不是'notifyDataSetChanged();'
我的适配器完美地显示了精美的动画,没有任何滞后
编辑:我从onBindViewHolder的位置得到了位置。
答案 6 :(得分:0)
如上文其他人所述,尽管您需要专门使用稳定的ID,但是在适配器上使用notifyDataSetChanged
时可以制作动画。如果您的商品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
}
}
,然后在您的适配器中:
private var stringToLongIdMap = StringToLongIdMap()
override fun getItemId(position: Int): Long {
val item = items[position]
return stringToLongIdMap.getLongId(item.id)
}
要考虑的另一件事,如果您将kotlin数据类用作适配器中的项,并且没有id,则可以将数据类本身的hashCode用作稳定的id(如果您确定项目属性组合在您的数据集中是唯一的):
override fun getItemId(position: Int): Long = items[position].hashCode().toLong()