「已解决」ItemTouchHelper 与刷新控件的滑动冲突

简书地址:https://www.jianshu.com/p/8b6b8aab3837

前言

    在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表示当前的状态,一共有三个值

1. ACTION_STATE_IDLE 表示没有任何手势,此时selected对应的应当是null;

2. ACTION_STATE_SWIPE 表示侧滑状态;

3. 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 //刷新控件置为可用

})
```

你可能感兴趣的:(Android)