两个列表间实现拖拽编辑

需要实现的效果如下:
1.列表自身可以拖拽交换
2.下边列表可以拖动到上边指定位置添加
3.下边列表拖入上方空白区域添加到末尾

image

一、同一个列表拖动编辑

方案比较简单,直接使用recyclerView 自身提供的API 就能实现

// 1 定义变量
private ItemTouchHelper itemTouchHelper;
private QuickSettingItemTouchHelperCallback svItemTouchHelperCallback;
private QuickSettingItemTouchHelperCallback getItemTouchCallBack() {
if (svItemTouchHelperCallback == null) {
svItemTouchHelperCallback = new QuickSettingItemTouchHelperCallback(
(ArrayList<ISVShortcut>) getPresenter().getSavedShortCutList(ShortcutManager.TYPE_ADDED_SETTING),
addedAdapter);
}
return svItemTouchHelperCallback;
}
// 2 调用
itemTouchHelper = new ItemTouchHelper(getItemTouchCallBack());
itemTouchHelper.attachToRecyclerView(recyclerView);
// 3 处理拖拽逻辑
public class QuickSettingItemTouchHelperCallback extends ItemTouchHelper.Callback {
private static final String TAG = "MyItemTouchHelper";
private ArrayList<ISVShortcut> mList;
private final ShortcutAdapter recycleViewAdapter;
// 是否开启拖拽的标记
private boolean dragEnable = false;
public QuickSettingItemTouchHelperCallback(ArrayList<ISVShortcut> list, ShortcutAdapter recycleViewAdapter) {
this.mList = list;
this.recycleViewAdapter = recycleViewAdapter;
recycleViewAdapter.setUpdateItemHelperListener(list1 -> mList = list1);
}
@Override
public int getMovementFlags(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {
final int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.START | ItemTouchHelper.END;
final int swipeFlags = 0;
return makeMovementFlags(dragFlags, swipeFlags);
}
/**
* 拖动中
*/
@Override
public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder target) {
recyclerView.getParent().requestDisallowInterceptTouchEvent(true);
//得到当前拖拽的viewHolder的Position
int fromPosition = viewHolder.getBindingAdapterPosition();
//拿到当前拖拽到的item的viewHolder
int toPosition = target.getBindingAdapterPosition();
if (fromPosition < toPosition) {
for (int i = fromPosition; i < toPosition; i++) {
Collections.swap(mList, i, i + 1);
}
} else {
for (int i = fromPosition; i > toPosition; i--) {
Collections.swap(mList, i, i - 1);
}
}
recycleViewAdapter.notifyItemMoved(fromPosition, toPosition);
recycleViewAdapter.updateDataList(mList, false);
Log.d(TAG, " fromPosition : " + fromPosition + " toPosition : " + toPosition);
return true;
}
@Override
public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {
}
/**
* 长按选中Item回调
*/
@Override
public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
super.onSelectedChanged(viewHolder, actionState);
}
/**
* 手指松开的时候回调
*/
@Override
public void clearView(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {
super.clearView(recyclerView, viewHolder);
}
public void setDragEnable(boolean dragEnable) {
this.dragEnable = dragEnable;
}
/**
* 重写拖拽不可用
*/
@Override
public boolean isLongPressDragEnabled() {
return dragEnable;
}
}

二、列表间的拖动

采用的是 View.startDragAndDrop 和 setOnDragListener 方法来实现相关功能(支持跨view)
参考文档

1、发起拖拽

// 给item设置长按换发起拖拽
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int position) {
// 设置一下代码,拖拽就能生效了
holder.itemView.setOnLongClickListener(view -> {
// 编辑模式,开启拖拽
if (dragEnable) {
// 拖拽后
Log.d(TAG, "post DragOpt.FROM_DEL");
ShortCutEvent fromEvent = new ShortCutEvent(this, statusShortcut, position);
fromEvent.setAdd(statusShortcut.isAdded());
QuickSettingDragHelper.startDrag(fromEvent);
// 传参,同一个window或者activity 里面,用传参的方式就能实现数据交互
ClipData data = ClipData.newPlainText("", String.valueOf(position));
// 拖拽背景(拖拽实跟随手势移动显示的view)
View.DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(holder.shortCutView.getViewBg());
view.startDragAndDrop(data, shadowBuilder, view, 0);
view.setVisibility(View.INVISIBLE);
}
return true;
});
}

2.监听拖拽事件

// 拖拽到item(带pos) 生效
holder.itemView.setOnDragListener(getDragInstance());
// 拖拽到 recyclerView 空白处(不带pos,添加至末尾)
recyclerView.setOnDragListener(getDragInstance());

主要实现逻辑在 DragListener 中实现,定义如下

public static class DragListener implements View.OnDragListener {
boolean isDropped = false;
boolean cancelDrag = false;
ShortcutAdapter.ShortcutListener shortcutListener;
public DragListener(ShortcutAdapter.ShortcutListener IFromDataListener) {
this.shortcutListener = IFromDataListener;
}
@Override
public boolean onDrag(View v, DragEvent event) {
int action = event.getAction();
RecyclerView toView = null;
int positionTo = -1;
switch (action) {
case DragEvent.ACTION_DRAG_STARTED:
cancelDrag = false;
Log.d(TAG, "ACTION_DRAG_STARTED: ");
break;
case DragEvent.ACTION_DRAG_LOCATION:
Log.d(TAG, "ACTION_DRAG_LOCATION: ");
break;
case DragEvent.ACTION_DROP:
Log.d(TAG, "ACTION_DROP: -------------");
// item 拖拽view 变化
v.setAlpha(1);
isDropped = true;
// 判断是 目的 列表的item 还是空白处
if (v.getId() == R.id.recyclerview) {
Log.d(TAG, " drop to rv");
} else {
Log.d(TAG, "ACTION_DROP to item");
}
...完成拖拽 数据更新,列表更新
return true;
case DragEvent.ACTION_DRAG_ENDED:
Log.d(TAG, "ACTION_DRAG_ENDED: cancelDrag " + cancelDrag + " \t isDropped :" + isDropped);
if (!cancelDrag && !isDropped) {
QuickSettingDragHelper.cancelDrag();
return true;
}
QuickSettingDragHelper.clearEvent();
break;
case DragEvent.ACTION_DRAG_ENTERED:
// 进入目标view
Log.d(TAG, "ACTION_DRAG_ENTERED: ");
if (v.getId() == R.id.recyclerview) {
toView = (MaxHeightRecyclerView) v;
// 获取pos
positionTo = toView.getAdapter().getItemCount();
} else {
toView = (MaxHeightRecyclerView) v.getParent();
positionTo = (int) v.getTag();
v.setAlpha(0.5f);
}
ShortcutAdapter adapterTo = (ShortcutAdapter) toView.getAdapter();
if (QuickSettingDragHelper.getFromEvent().getAdapter() == adapterTo) {
Log.d(TAG, "onDrag:同一个列表");
break;
}
Log.d(TAG, "positionTo " + positionTo);
ShortCutEvent toEvent1 = new ShortCutEvent(adapterTo, new PlaceholderShortCut(null), positionTo);
QuickSettingDragHelper.setToEvent(toEvent1);
break;
case DragEvent.ACTION_DRAG_EXITED:
Log.d(TAG, "ACTION_DRAG_EXITED: " + v);
if (v.getAlpha() < 1) {
v.setAlpha(1);
}
cancelDrag = true;
break;
default:
break;
}
if (!isDropped) {
View vw = (View) event.getLocalState();
vw.setVisibility(View.VISIBLE);
}
return true;
}
}

以上就是拖拽的过程中各个阶段回调,类似一次触摸事件的 down、up、cancel 等;

posted @   阿丟啊  阅读(690)  评论(4编辑  收藏  举报
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· DeepSeek R1 简明指南:架构、训练、本地部署及硬件要求
· NetPad:一个.NET开源、跨平台的C#编辑器
· PowerShell开发游戏 · 打蜜蜂
点击右上角即可分享
微信分享提示