列表拖动排序功能也算是比较常见的了。在RecycleView还没有出现的那个年代,依稀记得是重写GridView
实现拖拽,WindowManager
实现拖拽的镜像。
不过,现在好了,有了RecycleView
之后,一切都变得简单了。因为RecycleView
提供了拖动的回调ItemTouchHelper.Callback
,通过实现该类,会让我们少写很多代码。
先看一下,简化后的Demo效果图。
这里的实现的效果是:
① 第一个标签不可编辑
② 除了第一个标签外,其它标签可拖拽排序和删除
ItemTouchHelper.Callback的实现类
public class ItemDragCallback extends ItemTouchHelper.Callback {
private ChannelAdapter mAdapter;
private boolean mEdit;
public ItemDragCallback(ChannelAdapter mAdapter) {
this.mAdapter = mAdapter;
}
@Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
ChannelAdapter adapter = (ChannelAdapter) recyclerView.getAdapter();
mEdit = adapter.isEdit;
//是否是编辑状态
if (!mEdit) {
return 0;
}
int position = viewHolder.getLayoutPosition();
//第一个item不用交换
if (position == 0) {
return 0;
}
int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
int swipeFlags = 0;
return makeMovementFlags(dragFlags, swipeFlags);
}
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
int fromPosition = viewHolder.getAdapterPosition(); //拖动的position
int toPosition = target.getAdapterPosition(); //释放的position
int position = viewHolder.getLayoutPosition();
//第一个item不用交换
if (position == 0) {
return false;
}
mAdapter.itemMove(fromPosition, toPosition);
return true;
}
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
}
@Override
public void onChildDrawOver(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
super.onChildDrawOver(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
if (dX != 0 && dY != 0 || isCurrentlyActive) {
ChannelAdapter adapter = (ChannelAdapter) recyclerView.getAdapter();
mEdit = adapter.isEdit;
}
}
@Override
public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
super.onSelectedChanged(viewHolder, actionState);
if (actionState == ACTION_STATE_DRAG) {
//长按时调用
ChannelAdapter.ChannelHolder holder = (ChannelAdapter.ChannelHolder) viewHolder;
holder.name.setBackgroundColor(Color.parseColor("#FDFDFE"));
holder.name.setBackground(ContextCompat.getDrawable(ProjectApp.getApp(), R.drawable.shape_channel_bg));
holder.delete.setVisibility(View.GONE);
}
}
@Override
public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
super.clearView(recyclerView, viewHolder);
//松手时调用
ChannelAdapter.ChannelHolder holder = (ChannelAdapter.ChannelHolder) viewHolder;
holder.name.setBackground(ContextCompat.getDrawable(ProjectApp.getApp(), R.drawable.shape_channel_bg));
holder.delete.setVisibility(View.VISIBLE);
}
}
public class ChannelAdapter extends RecyclerView.Adapter {
private Context mContext;
private List mSortedList;
public boolean isEdit;//是否是编辑状态
public ChannelAdapter(Context mContext, List list) {
this.mContext = mContext;
mSortedList = list;
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(mContext).inflate(R.layout.item_channel, parent, false);
return new ChannelHolder(view);
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
setChannel((ChannelHolder) holder, mSortedList.get(position));
}
private void setChannel(final ChannelHolder holder, final ChannelBean bean) {
holder.name.setText(bean.getName());
int position = holder.getLayoutPosition();
//点击标签删除已选标签
holder.name.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (!bean.isLock()) {
if (isEdit) {
removeFromSelected(holder);
}
} else {
}
}
});
//长按进入编辑状态
holder.name.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
isEdit = true;
notifyDataSetChanged();
//返回true 防止长按拖拽事件跟点击事件冲突
return true;
}
});
//点击X删除已选标签
holder.delete.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
removeFromSelected(holder);
}
});
//是否是编辑状态且第一个不可编辑
if (isEdit&&position!=0) {
holder.delete.setVisibility(View.VISIBLE);
} else {
holder.delete.setVisibility(View.GONE);
}
}
/**
* 删除已选标签
* @param holder
*/
private void removeFromSelected(ChannelHolder holder) {
int position = holder.getLayoutPosition();
holder.delete.setVisibility(View.GONE);
notifyItemRemoved(position);
mSortedList.remove(position);
notifyDataSetChanged();
}
/**
* 对拖拽的元素进行排序
* @param fromPosition
* @param toPosition
*/
void itemMove(int fromPosition, int toPosition) {
if (fromPosition < toPosition) {
for (int i = fromPosition; i < toPosition; i++) {
Collections.swap(mSortedList, i, i + 1);
}
} else {
for (int i = fromPosition; i > toPosition; i--) {
Collections.swap(mSortedList, i, i - 1);
}
}
notifyItemMoved(fromPosition, toPosition);
}
@Override
public int getItemCount() {
return mSortedList == null ? 0 : mSortedList.size();
}
class ChannelHolder extends RecyclerView.ViewHolder {
TextView name;
ImageView delete;
public ChannelHolder(View itemView) {
super(itemView);
int validWidth = ScreenUtil.getScreenWidth() - Px2DpUtil.dp2px(mContext, 45);
int childWidth = validWidth / 4;
name = (TextView) itemView.findViewById(R.id.channel_name);
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(childWidth, Px2DpUtil.dp2px(mContext, 35));
params.setMargins(0, Px2DpUtil.dp2px(mContext, 5), 0, 0);
name.setLayoutParams(params);
name.setGravity(Gravity.CENTER);
delete = (ImageView) itemView.findViewById(R.id.channel_delete);
}
}
}
调用就比较简单了
ItemDragCallback callback = new ItemDragCallback(mAdapter);
ItemTouchHelper helper = new ItemTouchHelper(callback);
helper.attachToRecyclerView(mRecyclerView);
到这里就结束了。