如何解决为什么在 RecyclerView 中重复拖动动画?
我正在使用 itemtouchhelper 类来支持在我的 RecyclerView 中拖放。当我在它周围拖动一个项目时,它会按预期在视觉上更新(交换行)。一旦我放下该项目,就会发生另一个 ** 视觉** 拖动。例如(见下图),如果我将项目“a”从索引 0 拖动到索引 3,正确的列表显示项目“b”现在位于索引 0。他们回收视图重复操作并在索引 0 处获取新项目("b") 并将其拖动到索引 3!无论我从哪个索引拖动到哪个索引,都会发生这种重复拖动。
我将其称为 **visual** 拖动,因为我提交给 RecyclerView 的 listadapter 的列表已正确排序(通过日志验证)。如果我重新启动我的应用程序,列表的顺序是正确的。或者,如果我调用 notifyDataSetChanged(),在不需要的动画之后,它会正确排序。是什么导致了第二个动画?
编辑:根据文档,如果您在 areContentsTheSame() 方法 (DiffUtil) 中使用 equals() 方法,“此处错误地返回 false 将导致动画过多。”据我所知,我在下面的 POJO 文件中正确覆盖了此方法。我被难住了...
MainActivity.java
private void setListObserver() {
viewmodel.getAllItems().observe(this,new Observer<List<ListItem>>() {
@Override
// I have verified newList has the correct order through log statements
public void onChanged(List<ListItem> newList) {
adapterMain.submitList(newList);
}
});
}
...
// This method is called when item starts dragging
public void onSelectedChanged(@Nullable RecyclerView.ViewHolder viewHolder,int actionState) {
...
if (actionState == itemtouchhelper.ACTION_STATE_DRAG) {
currentList = new ArrayList<>(adapterMain.getCurrentList()); // get current list from adapter
}
...
}
// This method is called when item is dropped
public void clearView(@NonNull RecyclerView recyclerView,@NonNull RecyclerView.ViewHolder viewHolder) {
...
// I have verified that all code in this method is returning correct values through log statements.
// If I restart the app,everything is in the correct order
// this is position of the where the item was dragged to,gets its value from the onMoved method.
// it's the last "toPos" value in onMoved() after the item is dropped
int position = toPosition;
// Skip this code if item was deleted (indicated by -1). Otherwise,update the moved item
if(position != -1) {
ListItem movedItem = currentList.get(position);
// If dragged to the beginning of the list,subtract 1 from the prevIoUsly lowest
// positionInList value (the item below it) and assign it the moved item. This will ensure
// that it Now has the lowest positionInList value and will be ordered first.
if(position == 0) {
itemAfterPos = currentList.get(position + 1).getPositionInList();
movedItemNewPos = itemAfterPos - 1;
// If dragged to the end of list,add 1 to the positionInList value of the prevIoUsly
// largest value and assign to the moved item so it will be ordered last.
} else if (position == (currentList.size() - 1)) {
itemBeforePos = currentList.get(position - 1).getPositionInList();
movedItemNewPos = itemBeforePos + 1;
// If dragged somewhere in the middle of list,get the positionInList variable value of
// the items before and after it. They are used to compute the moved item's new
// positionInList value.
} else {
itemBeforePos = currentList.get(position - 1).getPositionInList();
itemAfterPos = currentList.get(position + 1).getPositionInList();
// Calculates the moved item's positionInList variable to be half way between the
// item above it and item below it
movedItemNewPos = itemBeforePos + ((itemAfterPos - itemBeforePos) / 2.0);
}
updateItemPosInDb(movedItem,movedItemNewPos);
}
private void updateItemPosInDb(ListItem movedItem,double movedItemNewPos) {
movedItem.setPositionInList(movedItemNewPos);
viewmodel.update(movedItem); // this updates the database which triggers the onChanged method
}
public void onMoved(@NonNull RecyclerView recyclerView,@NonNull RecyclerView.ViewHolder source,int fromPos,@NonNull RecyclerView.ViewHolder target,int toPos,int x,int y) {
Collections.swap(currentList,toPos,fromPos);
toPosition = toPos; // used in clearView()
adapterMain.notifyItemmoved(fromPos,toPos);
}
}).attachToRecyclerView(recyclerMain);
RecyclerAdapterMain.java
public class RecyclerAdapterMain extends listadapter<ListItem,RecyclerAdapterMain.ListItemHolder> {
// Registers MainActivity as a listener to checkBox clicks. Main will update database accordingly.
private CheckBoxListener checkBoxListener;
public interface CheckBoxListener {
void onCheckBoxClicked(ListItem item); // Method implemented in MainActivity
}
public void setCheckBoxListener(CheckBoxListener checkBoxListener) {
this.checkBoxListener = checkBoxListener;
}
public RecyclerAdapterMain() {
super(DIFF_CALLBACK);
}
// Static keyword makes DIFF_CALLBACK variable available to the constructor when it is called
// DiffUtil will compare two objects to determine if updates are needed
private static final DiffUtil.ItemCallback<ListItem> DIFF_CALLBACK =
new DiffUtil.ItemCallback<ListItem>() {
@Override
public boolean areItemsTheSame(@NonNull ListItem oldItem,@NonNull ListItem newItem) {
return oldItem.getId() == newItem.getId();
}
// Documentation - NOTE: if you use equals,your object must properly override Object#equals().
// Incorrectly returning false here will result in too many animations.
// As far as I can tell I am overriding the equals() properly in my POJO below
@Override
public boolean areContentsTheSame(@NonNull ListItem oldItem,@NonNull ListItem newItem) {
return oldItem.equals(newItem);
}
};
@NonNull
@Override
public ListItemHolder onCreateViewHolder(@NonNull ViewGroup parent,int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.recycler_item_layout_main,parent,false);
return new ListItemHolder(itemView);
}
@Override
public void onBindViewHolder(@NonNull ListItemHolder holder,int position) {
ListItem item = getItem(position);
Resources resources = holder.itemView.getContext().getResources();
holder.txtItemName.setText(item.getItemName());
holder.checkBox.setChecked(item.getIsChecked());
// Set the item to "greyed out" if checkBox is checked,normal color otherwise
if(item.getIsChecked()) {
holder.txtItemName.setTextColor(Color.LTGRAY);
holder.checkBox.setButtonTintList(ColorStateList
.valueOf(resources.getColor(R.color.checkedColor,null)));
} else {
holder.txtItemName.setTextColor(Color.BLACK);
holder.checkBox.setButtonTintList(ColorStateList
.valueOf(resources.getColor(R.color.uncheckedColor,null)));
}
}
public class ListItemHolder extends RecyclerView.ViewHolder {
private TextView txtItemName;
private CheckBox checkBox;
public ListItemHolder(@NonNull View itemView) {
super(itemView);
txtItemName = itemView.findViewById(R.id.txt_item_name);
// Toggle checkBox state
checkBox = itemView.findViewById(R.id.checkBox);
checkBox.setonClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
checkBoxListener.onCheckBoxClicked(getItem(getAdapterPosition()));
}
});
}
}
public ListItem getItemAt(int position) {
return getItem(position);
}
}
ListItem.java (POJO)
@Entity(tableName = "list_item_table")
public class ListItem {
@PrimaryKey(autoGenerate = true)
private long id;
private String itemName;
private boolean isChecked;
private double positionInList;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getItemName() {
return itemName;
}
public void setItemName(String itemName) {
this.itemName = itemName;
}
public void setChecked(boolean isChecked) {
this.isChecked = isChecked;
}
public boolean getIsChecked() {
return isChecked;
}
public void setPositionInList(double positionInList) {
this.positionInList = positionInList;
}
public double getPositionInList() {
return positionInList;
}
@Override
public boolean equals(@Nullable Object obj) {
ListItem item = new ListItem();
if(obj instanceof ListItem) {
item = (ListItem) obj;
}
return this.getItemName().equals(item.getItemName()) &&
this.getIsChecked() == item.getIsChecked() &&
this.getPositionInList() == item.getPositionInList();
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。