RecyclerView拖拽移动,长按小图标拖拽,侧滑删除

RecyclerView拖拽移动,长按小图标拖拽,侧滑删除

Github源码


长按小图标拖拽.gif

侧滑删除.gif


  • Android RecyclerView出来也很多年了,是非常成熟的控件,Github上工具一堆,做的非常全,侧滑、拖拽、动画都封装好的,但是工作需求,这种小功能就不用别人的,自己学习一下,写一个简单的代码即可实现。

  • RecyclerView的拖拽跟侧滑删除,其实就是使用 ItemTouchHelper 来实现,而我们只要写一下CallBack 继承 ItemTouchHelper.Callback(),重写里面的方法就行。

  • 要注意的一点是,完成CallBack直接长按就能实现拖拽,但是点小图标拖拽,其实就是加个开关,item要使用ontouch回调来处理,而不要使用长按longClick回调,因为在三星手机上,onLongClick回调是在CallBack之后的,就会无法拖拽,而国产系统都是longClick先回调,坑了我一把。

  • 一定会重写的三个方法,功能如下。

/**
 * 设置拖拽、滑动方向
 */
override fun getMovementFlags(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder): Int {
    if (!edit) {
        return 0
    }

    //拖拽方向
    val dragFlags =
        ItemTouchHelper.UP or ItemTouchHelper.DOWN or ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT

    //侧滑删除
    val swipeFlags =  ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT

    return makeMovementFlags(dragFlags, swipeFlags)
}

/**
 * 拖拽移动
 */
override fun onMove(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder): Boolean {
    //不同类型的item不能移动
    if (viewHolder.itemViewType != target.itemViewType) {
        return false
    }

    //拖动的position
    var fromPosition = viewHolder.adapterPosition
    //释放的position
    var targetPosition = target.adapterPosition

    onCallBack.onMove(fromPosition, targetPosition)
    return true
}

/**
 * 侧滑
 */
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
    onCallBack.remove(viewHolder,direction,viewHolder.layoutPosition)
}
  • 按自己需求重写其他的方法,功能如下。
/**
 * 长按时调用
 */
override fun onSelectedChanged(viewHolder: RecyclerView.ViewHolder?, actionState: Int) {
    super.onSelectedChanged(viewHolder, actionState)
    viewHolder?.let {
        //长按
        onCallBack.onSelectedChanged(viewHolder, actionState)
    }
}

/**
 * 松手时会最后调用
 */
override fun clearView(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder) {
    super.clearView(recyclerView, viewHolder)

    onCallBack.clearView(recyclerView, viewHolder)
}

/**
 * 是否支持长按,默认true
 */
override fun isLongPressDragEnabled(): Boolean {
    return super.isLongPressDragEnabled()
}

/**
 * 是否支持侧滑,默认true
 */
override fun isItemViewSwipeEnabled(): Boolean {
    return super.isItemViewSwipeEnabled()
}

  • 当我们移动item,数据换位置,就要自己写逻辑了。
/**
 * 移动item
 *
 * @param fromPosition   长按的item,position
 * @param targetPosition 要到达的position
 */
fun itemMove(adapter: RecyclerView.Adapter<RecyclerView.ViewHolder>, data: List<*>, fromPosition: Int, targetPosition: Int) {
    if (adapter == null || data.isEmpty()) {
        return
    }

    if (fromPosition < targetPosition) {
        for (i in fromPosition until targetPosition) {
            Collections.swap(data, i, i + 1)
        }
    } else {
        for (i in targetPosition until fromPosition) {
            Collections.swap(data, i, i + 1)
        }
    }
    adapter.notifyItemMoved(fromPosition, targetPosition)
}
  • 这整个callback就完成了。
class RecyclerTouchHelpCallBack(var onCallBack: OnHelperCallBack) : ItemTouchHelper.Callback() {
    //拖拽开关
    var edit = false


    /**
     * 设置拖拽、滑动方向
     */
    override fun getMovementFlags(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder): Int {
        if (!edit) {
            return 0
        }

        //拖拽方向
        val dragFlags =
            ItemTouchHelper.UP or ItemTouchHelper.DOWN or ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT

        //侧滑删除
        val swipeFlags =  ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT

        return makeMovementFlags(dragFlags, swipeFlags)
    }

    /**
     * 拖拽移动
     */
    override fun onMove(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder): Boolean {
        //不同类型的item不能移动
        if (viewHolder.itemViewType != target.itemViewType) {
            return false
        }

        //拖动的position
        var fromPosition = viewHolder.adapterPosition
        //释放的position
        var targetPosition = target.adapterPosition

        onCallBack.onMove(fromPosition, targetPosition)
        return true
    }

    /**
     * 侧滑
     */
    override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
        onCallBack.remove(viewHolder,direction,viewHolder.layoutPosition)
    }

    /**
     * 长按时调用
     */
    override fun onSelectedChanged(viewHolder: RecyclerView.ViewHolder?, actionState: Int) {
        super.onSelectedChanged(viewHolder, actionState)
        viewHolder?.let {
            //长按
            onCallBack.onSelectedChanged(viewHolder, actionState)
        }
    }

    /**
     * 松手时会最后调用
     */
    override fun clearView(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder) {
        super.clearView(recyclerView, viewHolder)

        onCallBack.clearView(recyclerView, viewHolder)
    }

    /**
     * 是否支持长按,默认true
     */
    override fun isLongPressDragEnabled(): Boolean {
        return super.isLongPressDragEnabled()
    }

    /**
     * 是否支持侧滑,默认true
     */
    override fun isItemViewSwipeEnabled(): Boolean {
        return super.isItemViewSwipeEnabled()
    }


    /**
     * 移动item
     *
     * @param fromPosition   长按的item,position
     * @param targetPosition 要到达的position
     */
    fun itemMove(adapter: RecyclerView.Adapter<RecyclerView.ViewHolder>, data: List<*>, fromPosition: Int, targetPosition: Int) {
        if (adapter == null || data.isEmpty()) {
            return
        }

        if (fromPosition < targetPosition) {
            for (i in fromPosition until targetPosition) {
                Collections.swap(data, i, i + 1)
            }
        } else {
            for (i in targetPosition until fromPosition) {
                Collections.swap(data, i, i + 1)
            }
        }
        adapter.notifyItemMoved(fromPosition, targetPosition)
    }

    interface OnHelperCallBack {
        fun onMove(fromPosition: Int, targetPosition: Int)

        fun onSelectedChanged(viewHolder: RecyclerView.ViewHolder, actionState: Int)

        fun clearView(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder)

        fun remove(viewHolder: RecyclerView.ViewHolder, direction: Int, position: Int)
    }
}
  • 使用简单。
callback = RecyclerTouchHelpCallBack(object : RecyclerTouchHelpCallBack.OnHelperCallBack {
    override fun onMove(fromPosition: Int, targetPosition: Int) {
        //移动item
        callback.itemMove(adapter, adapter.mData, fromPosition, targetPosition)
    }

    override fun onSelectedChanged(viewHolder: RecyclerView.ViewHolder, actionState: Int) {
        //选中的改变样式
        viewHolder.itemView.alpha = 1f
        viewHolder.itemView.scaleX = 1.2f
        viewHolder.itemView.scaleY = 1.2f
    }

    override fun clearView(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder) {
        //松手后不让操作,不然会点击全部范围拖拽
        callback.edit = false
        //完成移动,选中的改变样式
        adapter.mData
        viewHolder.itemView.alpha = 1f
        viewHolder.itemView.scaleX = 1f
        viewHolder.itemView.scaleY = 1f
    }

    override fun remove(viewHolder: RecyclerView.ViewHolder, direction: Int, position: Int) {
        // callback.edit = false,所以不会触发侧滑删除
       adapter.removeData(position)
    }
})

ItemTouchHelper(callback).attachToRecyclerView(rv_item)
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
您好,针对您的问题,我理解您想实现在 Android 应用中,用户可以通过按某个元素并拖动,实现多张图片的拖拽和拖放。我可以为您提供以下思路和代码示例: 首先,您需要为每一张图片设置一个触摸事件,以便用户可以通过按并拖动图片。例如,在您的布局文件中,可以为每个图片添加如下代码: ```xml <ImageView android:id="@+id/image1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/image1" android:tag="draggable" android:longClickable="true" android:onLongClick="onLongClickImage" /> ``` 其中,`android:tag="draggable"` 表示该元素可以被拖拽,`android:longClickable="true"` 表示该元素可以被按,`android:onLongClick="onLongClickImage"` 表示当用户按该元素时,会调用 `onLongClickImage` 方法。 接下来,您需要实现 `onLongClickImage` 方法,以便能够在用户按图片时启动拖拽事件。例如,可以使用 `View.OnLongClickListener` 接口来实现该方法: ```java public class MainActivity extends AppCompatActivity implements View.OnLongClickListener { private ImageView mSelectedImage; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 为每个图片添加按事件 findViewById(R.id.image1).setOnLongClickListener(this); findViewById(R.id.image2).setOnLongClickListener(this); findViewById(R.id.image3).setOnLongClickListener(this); } @Override public boolean onLongClick(View v) { // 记录选中的图片 mSelectedImage = (ImageView) v; // 启动拖拽事件 View.DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(v); v.startDragAndDrop(null, shadowBuilder, null, 0); return true; } } ``` 在这个例子中,当用户按某个图片时,会记录选中的图片并启动拖拽事件。拖拽事件使用 `View.startDragAndDrop` 方法来启动,并使用 `View.DragShadowBuilder` 创建一个拖拽的阴影。 最后,您需要实现 `View.OnDragListener` 接口来处理拖拽事件。例如,可以使用以下代码来实现: ```java public class MainActivity extends AppCompatActivity implements View.OnLongClickListener, View.OnDragListener { private ImageView mSelectedImage; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 为每个图片添加按事件 findViewById(R.id.image1).setOnLongClickListener(this); findViewById(R.id.image2).setOnLongClickListener(this); findViewById(R.id.image3).setOnLongClickListener(this); // 设置拖拽事件 findViewById(R.id.container).setOnDragListener(this); } @Override public boolean onLongClick(View v) { // 记录选中的图片 mSelectedImage = (ImageView) v; // 启动拖拽事件 View.DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(v); v.startDragAndDrop(null, shadowBuilder, null, 0); return true; } @Override public boolean onDrag(View v, DragEvent event) { switch (event.getAction()) { case DragEvent.ACTION_DRAG_STARTED: // 拖拽事件开始,返回 true 表示可以接收拖拽事件 return true; case DragEvent.ACTION_DRAG_ENTERED: // 拖拽事件进入容器,改变容器的背景色 v.setBackgroundColor(Color.YELLOW); break; case DragEvent.ACTION_DRAG_EXITED: // 拖拽事件离开容器,恢复容器的背景色 v.setBackgroundColor(Color.TRANSPARENT); break; case DragEvent.ACTION_DROP: // 拖拽事件释放,将图片从原位置移动到容器中 ViewGroup viewGroup = (ViewGroup) mSelectedImage.getParent(); viewGroup.removeView(mSelectedImage); ((ViewGroup) v).addView(mSelectedImage); break; case DragEvent.ACTION_DRAG_ENDED: // 拖拽事件结束,恢复容器的背景色 v.setBackgroundColor(Color.TRANSPARENT); break; } return true; } } ``` 在这个例子中,当用户将图片拖拽到容器中时,会将图片从原位置移动到容器中。您可以根据需要修改代码,实现更复杂的拖拽和拖放功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值