版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u014736095/article/details/89378858
公司的老项目需要加一个拖拽排序的功能,以前是用listview来实现的,自定义listview,然后再onInterceptTouchEvent中拦截DOWN的事件生成一个新的View,达到一个拖动的效果。这个思想是没有毛病,就是太繁琐了。Recycleview的效果就非常好,最后简单封装了一下,给大家使用:
首先我们需要一个工具类:DragRecycleViewHelper
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.helper.ItemTouchHelper;
import java.util.Collections;
import java.util.List;
/**
* 拖拽工具类,简单的上下拖拽可以直接使用{@link AbstrDragRecycleViewCallback}
* 默认为长按拖拽,如需触摸拖拽,触摸事件中调用{@link DragRecycleViewHelper#startDrag}即可
* Created by Gavin on 2019/4/17.
*/
public class DragRecycleViewHelper extends ItemTouchHelper {
/**
* Creates an ItemTouchHelper that will work with the given Callback.
* <p>
* You can attach ItemTouchHelper to a RecyclerView via
* {@link #attachToRecyclerView(RecyclerView)}. Upon attaching, it will add an item decoration,
* an onItemTouchListener and a Child attach / detach listener to the RecyclerView.
*
* @param callback The Callback which controls the behavior of this touch helper.
*/
private DragRecycleViewHelper(Callback callback) {
super(callback);
}
public DragRecycleViewHelper(RecyclerView recyclerView, ItemTouchHelper.Callback callback) {
super(callback);
attachToRecyclerView(recyclerView);
}
public abstract static class AbstrDragRecycleViewCallback extends ItemTouchHelper.Callback {
/**
* recycleview的adapter的数据源
*/
private List listData;
/**
* recycleview的headerview数量
*/
private final int HEADER_COUNT;
/**
* 拖拽监听
* @param listData adapter的数据源
* @param headerCount headerView条数
*/
public AbstrDragRecycleViewCallback(List listData,int headerCount) {
this.listData = listData;
this.HEADER_COUNT = headerCount;
}
@Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
int dragFlag = ItemTouchHelper.UP|ItemTouchHelper.DOWN;
if (isLimitDragItem(viewHolder,viewHolder.getAdapterPosition())) {
dragFlag = 0;
}
return makeMovementFlags(dragFlag,0);
}
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
if (isLimitSwap(viewHolder,target)) {
return false;
}else{
int fromIndex = viewHolder.getAdapterPosition();
int toIndex = target.getAdapterPosition();
if (fromIndex < toIndex) {
for (int i = fromIndex-1; i < toIndex- HEADER_COUNT; i++) {
Collections.swap(listData,i,i+ HEADER_COUNT);
}
}else{
for (int i = fromIndex-1; i > toIndex- HEADER_COUNT; i--) {
Collections.swap(listData,i,i- HEADER_COUNT);
}
}
recyclerView.getAdapter().notifyItemMoved(fromIndex,toIndex);
}
return true;
}
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
}
@Override
public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
super.onSelectedChanged(viewHolder, actionState);
onDragItemStart(viewHolder, actionState);
}
@Override
public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
super.clearView(recyclerView, viewHolder);
onDragItemFinish(viewHolder);
}
/**
* 该条viewholder是否被禁止被拖动,默认为长按拖拽,如需触摸拖拽,触摸事件中调用{@link DragRecycleViewHelper#startDrag}即可
* @param viewHolder
* @param holderPosition
* @return
*/
protected abstract boolean isLimitDragItem(RecyclerView.ViewHolder viewHolder, int holderPosition);
/**
* 是否禁止被交换,如果第1,2条不被交换,这里应该返回target.getAdapterPosition() < 2
* @param viewHolder
* @param targetViewHolder
* @return
*/
protected abstract boolean isLimitSwap(RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder targetViewHolder);
/**
* 拖动开始后触发
* @param viewHolder
* @param actionState
*/
protected void onDragItemStart(RecyclerView.ViewHolder viewHolder, int actionState){};
/**
* 拖动结束后触发
* 无须调用adapter.notifyDataSetChanged()了,已经被封装在父类了,直接写需要执行的逻辑即可。如保存操作
*
* @param viewHolder
*/
protected abstract void onDragItemFinish(RecyclerView.ViewHolder viewHolder);
}
}
使用例子:
//...
//mIndicatorSettingRv 你的RecyclerView
//mList 你的数据源
//headerViewCount 你的RecyclerView是否有headerView,如果有的话这里写headerView的数量,没有写0
DragRecycleViewHelper itemTouchHelper = new DragRecycleViewHelper(mIndicatorSettingRv, new DragRecycleViewHelper.AbstrDragRecycleViewCallback(mList, headerViewCount) {
@Override
protected boolean isLimitDragItem(RecyclerView.ViewHolder viewHolder, int holderPosition) {
return viewHolder.getAdapterPosition() < 2;
}
@Override
protected boolean isLimitSwap(RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder targetViewHolder) {
return targetViewHolder.getAdapterPosition() < 2;
}
@Override
protected void onDragItemFinish(RecyclerView.ViewHolder viewHolder) {
mIndicatorSettingAdapter.notifyDataSetChanged();
saveHqSetting(6);
}
});
//...