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)

Guess you like

Origin blog.csdn.net/qq_45204129/article/details/120652690