「已解决」ItemTouchHelper 与刷新控件的滑动冲突
前言
在RecyclerView中使用ItemTouchHelper可以轻松实现列表交换顺序的效果,基本用法就不说了,大家百度Google一下满大街都是。对于仅仅是列表的情况,无论是实现上下滑动拖拽还是左右滑动拖拽,ItemTouchHelper都能轻松应对。 但是当我将RecyclerView放入RefreshLayout(第三方控件或者SwipeRefreshLayout)中时,就产生了滑动冲突,是因为刷新控件本身就会监听我们的RecyclerView的滑动并在下滑时添加刷新头,而我们的 ItemTouchHelper 也会监听 RecyclerView 的滑动,当我长按触发拖拽再继续下拉拖拽,刷新头就出现了,这就是在竖直方向的拖拽情况下,两者产生的冲突。
解决
要解决无非就是在拖拽开启时将刷新控件的 enabled 属性置为 false ,在拖拽结束时将enabled 再置为 true ,刚开始我并没有找到 ItemTouchHelper 的对应拖拽开启的方法,但是可以使用 onSelectedChanged + actionState 来解决我们的问题
看看onSelectedChanged方法
override fun onSelectedChanged(viewHolder: RecyclerView.ViewHolder?, actionState: Int) {
super.onSelectedChanged(viewHolder, actionState)
}
其中actionState表示当前的状态,一共有三个值
-
ACTION_STATE_IDLE 表示没有任何手势,此时selected对应的应当是null;
-
ACTION_STATE_SWIPE 表示侧滑状态;
-
ACTION_STATE_DRAG 表示拖动状态。
在我们长按item开启了拖拽后,onSelectedChanged() 会被调用,在结束拖拽后,它也会被调用,那么我们只需要加上判断 actionState 是否处于 ACTION_STATE_DRAG 就能判断出是在刚触发拖拽还是已经结束拖拽,这部分代码是这样的
override fun onSelectedChanged(viewHolder: RecyclerView.ViewHolder?, actionState: Int) {
if (actionState != ItemTouchHelper.ACTION_STATE_IDLE) {
onSwipeStart()//自定义的开启拖拽时的回调方法(这里可以替换为 refreshLayout.enabled = false)
}else {
onSwiped()//自定义的拖拽结束时的回调方法(这里可以替换为refreshLayout.enabled = true)
}
super.onSelectedChanged(viewHolder, actionState)
}
这里我是为RecyclerView写了一个扩展方法,这样只需要直接使用‘recyClerView.attachItemSwipe’就轻松为RecyclerView添加了拖拽功能,当然这是 Kotlin语言才有的,使用Java的话就乖乖使用传参的方式吧,下面贴这个方法的完整代码
const val ITEM_SWIPE_VERTICAL =0
const val ITEM_SWIPE_HORIZENTAL =1
const val ITEM_SWIPE_FREE =2
fun RecyclerView.attachItemSwipe(decoration: Int, onSwipeStart: () -> Unit, onSwiped: () -> Unit) {
//互换位置
ItemTouchHelper(object : ItemTouchHelper.Callback() {
override fun getMovementFlags(
recyclerView: RecyclerView,
viewHolder: RecyclerView.ViewHolder
): Int =when (decoration) {
ITEM_SWIPE_VERTICAL -> makeMovementFlags(
ItemTouchHelper.UP or ItemTouchHelper.DOWN,
ItemTouchHelper.UP or ItemTouchHelper.DOWN
)
ITEM_SWIPE_HORIZENTAL -> makeMovementFlags(
ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT,
ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT
)
ITEM_SWIPE_FREE -> makeMovementFlags(
ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT or ItemTouchHelper.UP or ItemTouchHelper.DOWN,
ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT or ItemTouchHelper.UP or ItemTouchHelper.DOWN
)
else -> makeMovementFlags(
ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT or ItemTouchHelper.UP or ItemTouchHelper.DOWN,
ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT or ItemTouchHelper.UP or ItemTouchHelper.DOWN
)
}
override fun isLongPressDragEnabled(): Boolean =true
override fun onMoved(
recyclerView: RecyclerView,
viewHolder: RecyclerView.ViewHolder,
fromPos: Int,
target: RecyclerView.ViewHolder,
toPos: Int,
x: Int,
y: Int
) {
}
override fun onSelectedChanged(viewHolder: RecyclerView.ViewHolder?, actionState: Int) {
if (actionState != ItemTouchHelper.ACTION_STATE_IDLE) {
onSwipeStart()//自定义的开启拖拽时的回调方法(这里可以替换为 refreshLayout.enabled = false)
}else {
onSwiped()//自定义的拖拽结束时的回调方法(这里可以替换为 refreshLayout.enabled = true)
}
super.onSelectedChanged(viewHolder, actionState)
}
override fun onMove(
recyclerView: RecyclerView,
viewHolder: RecyclerView.ViewHolder,
target: RecyclerView.ViewHolder
): Boolean {
(adapter as MessageListAdapter).onItemMove(
viewHolder.adapterPosition, target.adapterPosition
)
return true
}
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {}
})
.attachToRecyclerView(this)
}
在Fragment(Activity)中:
//添加拖拽互换位置功能
recyclerViewLayout.attachItemSwipe(ITEM_SWIPE_VERTICAL, {
//onSwipeStart 交换开始
refreshLayout.isEnabled =false //刷新控件置为不可用
}, {
//onSwiped 交换完成
refreshLayout.isEnabled =true //刷新控件置为可用
})