2021-10-08 RecycleView的item实现拖拽

创建recycleView,将recycleView的item实现拖拽。

新建DefaultItemTouchHelper类,继承自ItemTouchHelper,DefaultItemTouchHelper不需要实现什么方法,它的任务就是将工作代理给Callback,然后将Callback作为参数传入。

新建DefaultItemTouchHelpCallback类。继承自ItemTouchHelper.callback()方法,这个类至少实现getMovementFlags()、onMove()、onSwiped()方法。

其中一些主要方法的作用是 :

getMovementFlags: 主要在这个方法中规定可进行拖拽的方向,可进行滑动的方向。

onMove: 主要是如果实现拖拽,进行拖拽的item,可以在这进行子view的位置的替换

onSwiped: 主要是如果实现滑动,可以在这里进行子View的位置的删除操作。

isItemViewSwipeEnabled() : 返回值是是否支持滑动

isLongPressDragEnabled : 返回值是是否支持拖拽

onSelectedChanged : 在这里更新UI,当被拖动的或者是被滑动的viewHolder改变时调用,actionState会返回当前ViewHolder的状态,有三个状态值。

* action_state_swipe : 当View刚被滑动时返回
* action_state_drag : 当View刚被拖动时返回
* action_state_idle : 当View即没被拖动也没有被滑动时或者是滑动状态还没被触发时,返回这个状态
* 在这里就可以进行拖动时候进行高亮显示,

clearView: 刚刚说在onSelectedChanged中可以进行在view改变位置时更新UI,比如说进行高亮显示等,那么在clearView中是进行UI的复原,比如进行高亮显示的取消。

主要的方法就是以上几个。

​ 但是,如果说我们直接在DefaultItemTouchHelpCallback类中将所有的方法都规定实现,本来是定义一个callback就可以了,传给ItemTouchHelper生成实例,ItemTouchHelper的作用就是RecycleView进项绑定,其余的都在callback进行处理,但是如果只是定义一个callback的话自己进行实现自己需要的拖拽,那么只能实现这一种情况,就比如我这里要实现的是左右拖拽,这样这个callback就是一个定制callback,如果遇到其他也需要进行拖拽处理的情况需要重新建个类去实现。

​ 所以这里是定义一个接口,新建个ItemTouchDelegate接口,分别空实现onMove(),onSwiped(),uiOnSwiping(),uiOnDragging(),uiOnClearView(),其中getMovementFlags()我们默认实现,让ItemTouchHelper进支持上下方向的拖动、其他行为禁止,也即能满足我们的需求。

所以创建ItemTouchDeleGate接口

import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.ItemTouchHelper.*
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
/**
 本来是定义一个callback就可以了,传给ItemTouchHelper生成实例,ItemTouchHelper的作用就是与RecycleView进项绑定
 其余的都在callback进行处理,
 但是如果只是定义一个callback的话自己进行实现自己需要的拖拽,那么只能实现这一种情况,就比如我这里要实现的是左右拖拽,这样这个callback就是一个定制callback
 如果遇到其他也需要进行拖拽处理的情况需要重新建个类去实现。
 所以这里是定义一个接口,新建个ItemTouchDelegate接口,
 分别空实现onMove(),onSwiped(),uiOnSwiping(),uiOnDragging(),uiOnClearView(),
 其中getMovementFlags()我们默认实现,让ItemTouchHelper进支持上下方向的拖动、其他行为禁止,也即能满足我们的需求。
 */

interface ItemTouchDelegate {

    //getMovementFlags中定义是否处理拖拽事件和滑动事件,以及定义拖拽的方向和滑动的方向
    //ragFlags 是拖拽标志,swipeFlags是滑动标志,我们把swipeFlags 都设置为0,表示不处理滑动操作。
    fun getMovementFlags(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder): Array<Int> {
        val layoutManager = recyclerView.layoutManager
        var swipeFlag = 0
        var dragFlag = 0
        if (layoutManager is LinearLayoutManager) {
            if (layoutManager.orientation == LinearLayoutManager.VERTICAL) {
                swipeFlag = 0   // 不允许滑动
                dragFlag = (UP or DOWN)     // 允许上下拖拽
            } else {
                swipeFlag = 0
                dragFlag = (LEFT or RIGHT)  // 允许左右拖拽
            }
        }else if(layoutManager is GridLayoutManager) {
            dragFlag = (UP or DOWN or LEFT or RIGHT) //允许上下左右进行拖拽
            swipeFlag = 0
        }

        return arrayOf(dragFlag, swipeFlag)
    }

    //当我们设置了非0的dragFlag时,可以进行item的拖拽,在拖拽的过程中不断地回调onMove()方法
    //因为拖拽的过程中两个item的位置进行了改变,我们应该知道两个item的所处位置的ViewHolder,
    //然后让两个ViewHolder进行数据集的交换并调用Adapter的notifyItemMoved来刷新item
    fun onMove(srcPosition: Int, targetPosition:Int): Boolean = true

    //当用户正在滑动子View时调用,可以在这里进行子View的删除操作。
    fun onSwiped(position: Int, direction: Int) {}

    // 刚开始滑动时,需要进行的UI操作
    fun uiOnSwiping(viewHolder: RecyclerView.ViewHolder?) {}

    // 刚开始拖动时,需要进行的UI操作
    fun uiOnDragging(viewHolder: RecyclerView.ViewHolder?) {}

    // 用户释放与当前itemView的交互时,可在此方法进行UI的复原
    fun uiOnClearView(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder) {}
}

在DefaultItemTouchHelpCallback 中进行实现

import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.ItemTouchHelper.ACTION_STATE_DRAG
import androidx.recyclerview.widget.ItemTouchHelper.ACTION_STATE_SWIPE
import androidx.recyclerview.widget.RecyclerView
import org.jetbrains.annotations.NotNull
import javax.inject.Inject

class DefaultItemTouchHelpCallback(@NotNull val helperDelegate : ItemTouchDelegate) :
    ItemTouchHelper.Callback () {

    //dragFlags确定拖动方向,swipeFlags确定滑动删除
    //一个是用户长按后的拖拽状态,一个是手指左右滑动的滑动状态
    private var canDrag: Boolean? = null
    private var canSwipe: Boolean? = null

    fun setDragEnable(enable: Boolean) {
        canDrag = enable
    }

    fun setSwipeEnable(enable: Boolean) {
        canSwipe = enable
    }

    override fun getMovementFlags(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder): Int {
        val flags = helperDelegate.getMovementFlags(recyclerView, viewHolder)
        return if (flags != null && flags.size >= 2) {
            makeMovementFlags(flags[0], flags[1])
        } else makeMovementFlags(0, 0)
    }

    override fun onMove(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder): Boolean {
        return helperDelegate.onMove(viewHolder.adapterPosition, target.adapterPosition)
    }

    override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
        helperDelegate.onSwiped(viewHolder.adapterPosition, direction)
    }

    override fun isItemViewSwipeEnabled(): Boolean {
        return canSwipe == true
    }

    override fun isLongPressDragEnabled(): Boolean {
        return canDrag == true
    }

    /**
     * 更新UI
     * 当被拖动或者是被滑动的ViewHolder改变时调用,actionState会返回当前viewHolder的状态,有三个值
     * action_state_swipe : 当View刚被滑动时返回
     * action_state_drag : 当View刚被拖动时返回
     * Action_state_idle : 当View即没被拖动也没有被滑动时或者是滑动状态还没被触发时,返回这个状态
     * 在这里就可以进行拖动时候进行高亮显示,
     */
    override fun onSelectedChanged(viewHolder: RecyclerView.ViewHolder?, actionState: Int) {
        super.onSelectedChanged(viewHolder, actionState)
        when(actionState) {
            ACTION_STATE_SWIPE -> {
                helperDelegate.uiOnSwiping(viewHolder)
            }
            ACTION_STATE_DRAG -> {
                helperDelegate.uiOnDragging(viewHolder)
            }
        }
    }

    /**
     * 更新UI
     * 当View被拖动或者是滑动完后并且已经结束了运动动画时调用,进行uI的复原,例如当View固定位置后,让View的显示取消高亮
     */
    override fun clearView(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder) {
        super.clearView(recyclerView, viewHolder)
        helperDelegate.uiOnClearView(recyclerView, viewHolder)
    }


}

DefaultItemTouchHelper中就是将callback实例传入,所以将创建好的DefaultItemTouchHelpCallback传入,


import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.RecyclerView

class DefaultItemTouchHelper(private val callback : DefaultItemTouchHelpCallback): ItemTouchHelper(callback) {
    fun setDragEnable(enable: Boolean) {
        callback.setDragEnable(enable)
    }

    fun setSwipeEnable(enable: Boolean) {
        callback.setSwipeEnable(enable)
    }

    override fun startDrag(viewHolder: RecyclerView.ViewHolder) {
        super.startDrag(viewHolder)
    }
}

使用时就直接在recycleView初始化后进行对callback的初始化,将需要实现的方法进行实现,然后将callback实例传入TouchHelper中,这样recycleView的子view就可以进行拖拽了。

最主要要实现的方法就是onMove、onSwiped、onSelectedChanged、clearView方法。

var itemTouchHelpCallback = DefaultItemTouchHelpCallback(object : ItemTouchDelegate{
            override fun onMove(srcPosition: Int, targetPosition: Int): Boolean {
                if(mViewModel.getTryList().size > 1 && srcPosition < mViewModel.getTryList().size && targetPosition < mViewModel.getTryList().size){
                    Collections.swap(mViewModel.getTryList(), srcPosition, targetPosition)
                    tryAdapter.notifyItemMoved(srcPosition, targetPosition)
                    return true
                }

                return false
            }

//        override fun uiOnDragging(viewHolder: RecyclerView.ViewHolder?) {
//            viewHolder?.itemView?.setBackgroundColor(Color.parseColor("@drawable/gray_round_bg_16"))
//        }
//
//        override fun uiOnClearView(
//            recyclerView: RecyclerView,
//            viewHolder: RecyclerView.ViewHolder
//        ) {
//            viewHolder.itemView.setBackgroundColor(Color.parseColor("@drawable/white_round_bg_16"))
//        }
        })
        itemTouchHelper = DefaultItemTouchHelper(itemTouchHelpCallback)
        itemTouchHelper.attachToRecyclerView(mBinding.rcyTryTool)
        itemTouchHelper.setDragEnable(true)
        itemTouchHelper.setSwipeEnable(false)
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
实现两个RecyclerView item之间的拖拽动画,可以使用ItemTouchHelper类。以下是基本步骤: 1. 创建一个实现ItemTouchHelper.Callback的类,重写以下方法: - onMove():当用户拖动item时,返回true,同时交换item的位置。 - onSwiped():当用户滑动item时,执行删除或其他操作。 - getMovementFlags():设置拖拽和滑动的方向。 2. 在RecyclerView的Adapter中实现ItemTouchHelperAdapter接口,重写以下方法: - onItemMove():当item被移动时,将item的位置交换。 - onItemDismiss():当item被删除时,执行删除操作。 3. 在Activity或Fragment中创建ItemTouchHelper实例,并将其附加到RecyclerView上。 4. 在Adapter中实现动画效果,可以使用ItemAnimator类。例如,使用DefaultItemAnimator类实现默认的动画效果。 以下是示例代码: ```kotlin class MyItemTouchHelperCallback(private val adapter: ItemTouchHelperAdapter) : ItemTouchHelper.Callback() { override fun getMovementFlags(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder): Int { val dragFlags = ItemTouchHelper.UP or ItemTouchHelper.DOWN val swipeFlags = ItemTouchHelper.START or ItemTouchHelper.END return makeMovementFlags(dragFlags, swipeFlags) } override fun onMove(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder): Boolean { adapter.onItemMove(viewHolder.adapterPosition, target.adapterPosition) return true } override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) { adapter.onItemDismiss(viewHolder.adapterPosition) } } interface ItemTouchHelperAdapter { fun onItemMove(fromPosition: Int, toPosition: Int) fun onItemDismiss(position: Int) } class MyAdapter(private val data: MutableList<String>) : RecyclerView.Adapter<MyAdapter.ViewHolder>(), ItemTouchHelperAdapter { // ... override fun onItemMove(fromPosition: Int, toPosition: Int) { // 交换item Collections.swap(data, fromPosition, toPosition) notifyItemMoved(fromPosition, toPosition) } override fun onItemDismiss(position: Int) { // 删除item data.removeAt(position) notifyItemRemoved(position) } // ... } // 在Activity或Fragment中 val callback = MyItemTouchHelperCallback(adapter) val touchHelper = ItemTouchHelper(callback) touchHelper.attachToRecyclerView(recyclerView) ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值