我想在前面说过我正在重置适配器,因为当调用clearView时我正在对行进行动画处理。在第一次传递时,在我重置适配器之前,notifyItemMoved按预期工作,切换视图。只有在我重置适配器后才会出现问题。
话虽如此,在我用setAdapter()
重置适配器之后调用了notifyItemMoved,但是当试图移动一个位置超出它自己的位置时,看起来似乎......“卡住了”。将onMove
中的日志记录放入我的ItemTouchHelper中,发现它在尝试移动到另一个位置时每秒都会被调用,就像onChildDraw
一样。此外,日志记录显示框架在调用时onMove(RecyclerView recyclerview, ViewHolder source, ViewHolder target)
来源保持不变是有道理的。因此,例如,如果我试图从位置1移动到2源将是1并且目标将是2.但是如果我尝试进一步移动(让我们说位置3),位置1处的视图将不会移动并且源在它开始时停留在1,目标是3.这一直持续到列表的末尾。
是否有理由重置适配器会导致notifyItemMoved不起作用?
以下是代码示例。我删除了实际类和方法的名称以保持匿名。
@Override
public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
ViewHolder previousViewHolder;
ViewHolder nextViewHolder;
int actualNextPosition = (recyclerView.getChildAdapterPosition(viewHolder.itemView) + 1) - ((LinearLayoutManager)recyclerView.getLayoutManager()).findFirstVisibleItemPosition();
int actualPreviousPosition = (recyclerView.getChildAdapterPosition(viewHolder.itemView) - 1) - ((LinearLayoutManager)recyclerView.getLayoutManager()).findFirstVisibleItemPosition();
if ((Math.abs(mScrolledAmount) / viewHolder.itemView.getHeight() * 100 >= 65)) {
//We've reached the threshold for dropping a view into its rightful place
if (mScrolledAmount < 0) {
//we've dragged up and released
if (recyclerView.getChildAt(actualPreviousPosition) != null) {
previousViewHolder = ((ViewHolder) recyclerView
.getChildAt(actualPreviousPosition)
.getTag());
TranslateAnimation currentViewAnimator = new TranslateAnimation(0,0, 0, -viewHolder.itemView.getHeight() + Math.abs(mScrolledAmount));
currentViewAnimator.setDuration(250);
viewHolder.itemView.startAnimation(currentViewAnimator);
TranslateAnimation previousViewAnimator = new TranslateAnimation(0,0, 0, viewHolder.itemView.getHeight() - Math.abs(previousViewHolder.itemView.getTranslationY()));
previousViewAnimator.setDuration(250);
previousViewHolder.itemView.startAnimation(previousViewAnimator);
previousViewAnimator.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
LogUtil.d(TAG, "Current Translation" + viewHolder.itemView.getTranslationY() + "PREVIOUS" + previousViewHolder.itemView.getTranslationY());
((Adapter) recyclerView.getAdapter()).resetAdapterAndMakeCall(viewHolder.getAdapterPosition(), previousViewHolder.getAdapterPosition());
mViewHasMoved = false;
clearAfterAnimate(recyclerView, viewHolder, previousViewHolder);
mClearCallback.clearTouch();
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
}
}
else {
//we've dragged down and released
if (recyclerView.getChildAt(actualNextPosition) != null) {
nextViewHolder = ((ViewHolder) recyclerView
.getChildAt(actualNextPosition)
.getTag());
//((Adapter) recyclerView.getAdapter()).resetAdapterAndMakeCall(viewHolder.getAdapterPosition(), nextViewHolder.getAdapterPosition());
TranslateAnimation currentViewAnimator = new TranslateAnimation(0,0, 0, viewHolder.itemView.getHeight() - mScrolledAmount);
currentViewAnimator.setDuration(250);
viewHolder.itemView.startAnimation(currentViewAnimator);
TranslateAnimation nextViewAnimator = new TranslateAnimation(0,0, 0, -viewHolder.itemView.getHeight() + Math.abs(nextViewHolder.itemView.getTranslationY()));
nextViewAnimator.setDuration(250);
nextViewHolder.itemView.startAnimation(nextViewAnimator);
nextViewAnimator.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
//LogUtil.d(TAG, "Current Translation" + viewHolder.itemView.getTranslationY() + "PREVIOUS" + nextViewHolder.itemView.getTranslationY());
((Adapter) recyclerView.getAdapter()).resetAdapterAndMakeCall(viewHolder.getAdapterPosition(), nextViewHolder.getAdapterPosition());
mViewHasMoved = false;
clearAfterAnimate(recyclerView, viewHolder, nextViewHolder);
mClearCallback.clearTouch();
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
}
//Translate Animation positive translates up negative translates down
}
}
else if ((Math.abs(mScrolledAmount) / viewHolder.itemView.getHeight() * 100 < 65)) {
if (mScrolledAmount < 0) {
//dragged up and released
TranslateAnimation currentViewAnimator = new TranslateAnimation(0,0, mScrolledAmount, 0);
currentViewAnimator.setDuration(250);
currentViewAnimator.setFillAfter(true);
viewHolder.itemView.startAnimation(currentViewAnimator);
}
else {
//dragged down and released
TranslateAnimation currentViewAnimator = new TranslateAnimation(0,0, mScrolledAmount, 0);
currentViewAnimator.setDuration(250);
currentViewAnimator.setFillAfter(true);
viewHolder.itemView.startAnimation(currentViewAnimator);
}
super.clearView(recyclerView, viewHolder);
if (recyclerView.getChildAt(actualPreviousPosition) != null) {
previousViewHolder = ((ViewHolder) recyclerView
.getChildAt(actualPreviousPosition)
.getTag());
if (previousViewHolder.itemView != null) {
super.clearView(recyclerView, previousViewHolder);
}
}
if (recyclerView.getChildAt(actualNextPosition) != null) {
nextViewHolder = ((ViewHolder) recyclerView
.getChildAt(actualNextPosition)
.getTag());
if (nextViewHolder.itemView != null) {
super.clearView(recyclerView, nextViewHolder);
}
}
}
LogUtil.d(TAG, "Cleared");
viewHolder.itemView.setAlpha(ALPHA_FULL);
if (viewHolder instanceof ItemTouchHelperViewHolder) {
// Tell the view holder it's time to restore the idle state
ItemTouchHelperViewHolder itemViewHolder = (ItemTouchHelperViewHolder) viewHolder;
// I have this if the user lifts their finger up and they've moved to another position or
mHandler.postDelayed(() -> {
if (mViewHasMoved) {
mClearCallback.clearTouch();
mViewHasMoved = false;
}
}, 250);
itemViewHolder.onItemClear();
}
}
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder source, RecyclerView.ViewHolder target) {
if (source.getItemViewType() != target.getItemViewType()) {
return false;
}
// Notify the adapter of the move
LogUtil.d(TAG, Integer.toString(source.getAdapterPosition()) + Integer.toString(target.getAdapterPosition()));
mAdapter.onItemMove(source.getAdapterPosition(), target.getAdapterPosition());
super.clearView(recyclerView, target);
mViewHasMoved = true;
return true;
}
//In a fragment
public void resetAdapterAndMakeCall(int fromPosition, int toPosition, List<Data> data) {
LinearLayoutManager manager = (LinearLayoutManager) recyclerview.getLayoutManager();
int firstItem = manager.findFirstVisibleItemPosition();
View firstItemView = manager.findViewByPosition(firstItem);
float topOffset = firstItemView.getTop();
mAdapter = new Adapter(getActivity(), data, this);
recycler.setAdapter(adapter);
manager.scrollToPositionWithOffset(firstItem, (int) topOffset);
}
@Override
public boolean onItemMove(int fromPosition, int toPosition) {
Collections.swap(list, fromPosition, toPosition);
// The problem with doing a swap here for like order is that the adapter starts the position from 0
// and we need to send the position to the server without a 0.
notifyItemMoved(fromPosition, toPosition);
mViewHasMoved = true;
return true;
}