RecyclerView实现拖动效果,并解决里面的坑。
先上效果
创建SimpleItemTouchHelper
public class SimpleItemTouchHelper extends ItemTouchHelper.Callback {
private Activity activity;
private OnMoveAndSwipedListener mAdapter;
public final float ALPHA_FULL = 1.0f;
public SimpleItemTouchHelper(Activity activity, OnMoveAndSwipedListener listener) {
this.activity = activity;
this.mAdapter = listener;
}
/**
* 是否可以拖动
*
* @return
*/
@Override
public boolean isLongPressDragEnabled() {
return true;
}
/**
* 是否可以滑动
*
* @return
*/
@Override
public boolean isItemViewSwipeEnabled() {
return false;
}
/**
* 拖动的方向以及侧滑的方向
*/
@Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
//设置拖拽方向为上下
final int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
//设置侧滑方向 start从右到往左 end从左往右
final int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END;
return makeMovementFlags(dragFlags, swipeFlags);
}
/**
* 拖动item时回调
*/
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
//当拖拽的item拖拽到另一种item上时不允许拖拽
if (viewHolder.getItemViewType() != target.getItemViewType()) {
return false;
}
//回调adapter中的onItemMove方法
mAdapter.onItemMove(viewHolder.getAdapterPosition(), target.getAdapterPosition());
return true;
}
/**
* 拖动时会回调.在这里可以绘制item
*/
@Override
public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) {
// Fade out the view as it is swiped out of the parent's bounds
final float alpha = ALPHA_FULL - Math.abs(dX) / (float) viewHolder.itemView.getWidth();
viewHolder.itemView.setAlpha(alpha);
viewHolder.itemView.setTranslationX(dX);
} else {
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
}
}
/**
* 侧滑item后会回调
*/
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
mAdapter.onItemDismiss(viewHolder.getAdapterPosition());
}
}
OnMoveAndSwipedListener接口回调
public interface OnMoveAndSwipedListener {
boolean onItemMove(int fromPosition, int toPosition);
void onItemDismiss(int position);
}
在你的Adapter中实现 OnMoveAndSwipedListener接口
public boolean onItemMove(int fromPosition, int toPosition) {
if (fromPosition < toPosition) {
//从上往下拖动,每滑动一个item,都将list中的item向下交换,向上滑同理。
for (int i = fromPosition; i < toPosition; i++) {
Collections.swap(mList, i, i + 1);//交换数据源两个数据的位置
}
} else if(fromPosition > toPosition){
for (int i = fromPosition; i > toPosition; i--) {
Collections.swap(mList, i, i - 1);//交换数据源两个数据的位置
}
}
//刷新列表数据
notifyItemMoved(fromPosition, toPosition);
return true;
}
@Override
public void onItemDismiss(int position) {
}
在这里我没有实现侧滑删除,分享一个这里遇到的问题
重点在这里
因为onItemMove
中的 notifyItemMoved(fromPosition, toPosition);
会把索引值一块移动,下次再取值时,就会出现错乱现象,下面是我处理的方案。
在这里加入notifyItemRangeChanged(Math.min(fromPosition, toPosition), Math.abs(fromPosition - toPosition) +1);
会将改动的position刷新一遍,从而再次取值时,不会再出现错乱现象。