两个列表间实现拖拽编辑
需要实现的效果如下:
1.列表自身可以拖拽交换
2.下边列表可以拖动到上边指定位置添加
3.下边列表拖入上方空白区域添加到末尾
一、同一个列表拖动编辑
方案比较简单,直接使用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 等;
本文来自博客园,作者:阿丟啊,转载请注明原文链接:https://www.cnblogs.com/qiyuexiaxun/p/17458184.html
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· DeepSeek R1 简明指南:架构、训练、本地部署及硬件要求
· NetPad:一个.NET开源、跨平台的C#编辑器
· PowerShell开发游戏 · 打蜜蜂