前言:基于RecycleView实现拖动效果,其实很简单,只需使用系统提供的ItemTouchHelper即可满足大部分需求。
实现:
1、创建ItemTouchHelper,在CallBack中处理业务
(1)getMovementFlags()设置允许拖动、滑动的方向
(2)onMove()拖动过程不断调用,用于交换item
(3)onSelectedChanged()长按选中回调,可以用作选中背景高亮
(4)clearView()结束拖动回调,可以用作还原选中背景
2、关联RecycleView,赋予滑动能力
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val tableList = ArrayList<String>()
for (i in 1..200) {
tableList.add("桌(${i})")
}
rv_table.layoutManager = GridLayoutManager(this, 5)
TableAdapter().let {
it.mTableList = tableList
rv_table.adapter = it
}
val itemTouchHelper = ItemTouchHelper(object : ItemTouchHelper.Callback() {
override fun getMovementFlags(
recyclerView: RecyclerView,
viewHolder: RecyclerView.ViewHolder
): Int {
//拖动方向
val dargFlags =
ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT or ItemTouchHelper.UP or ItemTouchHelper.DOWN
//滑动方向
val swipeFlags = ItemTouchHelper.UP or ItemTouchHelper.DOWN
//设置拖动、滑动方向
return makeMovementFlags(dargFlags, swipeFlags)
}
override fun onMove(
recyclerView: RecyclerView,
viewHolder: RecyclerView.ViewHolder,
target: RecyclerView.ViewHolder
): Boolean {
//拖动的ViewHolder位置
val fromPosition = viewHolder.adapterPosition
//经过的ViewHolder位置
val toPosition = target.adapterPosition
when{
fromPosition < toPosition -> {//向后拖动,和位置+1进行交换
for (i in fromPosition..toPosition) {
Collections.swap(tableList, i, i + 1)
}
recyclerView.adapter?.notifyItemMoved(fromPosition, toPosition)
}
fromPosition > toPosition -> {//向前拖动,和位置-1进行交换
for (i in fromPosition..toPosition) {
Collections.swap(tableList, i, i - 1)
}
recyclerView.adapter?.notifyItemMoved(fromPosition, toPosition)
}
}
return true
}
override fun onSelectedChanged(viewHolder: RecyclerView.ViewHolder?, actionState: Int) {
super.onSelectedChanged(viewHolder, actionState)
//长按选中更新要拖动的ViewHolder背景色
(viewHolder as? TableAdapter.TableViewHolder)?.tvTabe?.setBackgroundResource(R.color.colorPrimary)
}
override fun clearView(
recyclerView: RecyclerView,
viewHolder: RecyclerView.ViewHolder
) {
super.clearView(recyclerView, viewHolder)
(viewHolder as TableAdapter.TableViewHolder).tvTabe.setBackgroundResource(R.color.colorAccent)
}
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {}
})
//赋予RecycleView拖动能力
itemTouchHelper.attachToRecyclerView(rv_table)
}
进阶
场景一:禁止部分item拖动(如第1项禁止拖动)
1、禁用默认的拖动:CallBack中isLongPressDragEnabled()返回false
2、在自定义实现的item长按事件里,对于满足条件的执行拖动操作
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val tableList = ArrayList<String>()
for (i in 1..200) {
tableList.add("桌(${i})")
}
rv_table.layoutManager = GridLayoutManager(this, 5)
val itemTouchHelper = ItemTouchHelper(object : ItemTouchHelper.Callback() {
override fun getMovementFlags(
recyclerView: RecyclerView,
viewHolder: RecyclerView.ViewHolder
): Int {
//拖动方向
val dargFlags =
ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT or ItemTouchHelper.UP or ItemTouchHelper.DOWN
//滑动方向
val swipeFlags = ItemTouchHelper.UP or ItemTouchHelper.DOWN
//设置拖动、滑动方向
return makeMovementFlags(dargFlags, swipeFlags)
}
override fun onMove(
recyclerView: RecyclerView,
viewHolder: RecyclerView.ViewHolder,
target: RecyclerView.ViewHolder
): Boolean {
//拖动的ViewHolder位置
val fromPosition = viewHolder.adapterPosition
//经过的ViewHolder位置
val toPosition = target.adapterPosition
when{
fromPosition < toPosition -> {//向后拖动,和位置+1进行交换
for (i in fromPosition..toPosition) {
Collections.swap(tableList, i, i + 1)
}
recyclerView.adapter?.notifyItemMoved(fromPosition, toPosition)
}
fromPosition > toPosition -> {//向前拖动,和位置-1进行交换
for (i in fromPosition..toPosition) {
Collections.swap(tableList, i, i - 1)
}
recyclerView.adapter?.notifyItemMoved(fromPosition, toPosition)
}
}
return true
}
override fun onSelectedChanged(viewHolder: RecyclerView.ViewHolder?, actionState: Int) {
super.onSelectedChanged(viewHolder, actionState)
//长按选中更新要拖动的ViewHolder背景色
(viewHolder as? TableAdapter.TableViewHolder)?.tvTabe?.setBackgroundResource(R.color.colorPrimary)
}
override fun clearView(
recyclerView: RecyclerView,
viewHolder: RecyclerView.ViewHolder
) {
super.clearView(recyclerView, viewHolder)
(viewHolder as TableAdapter.TableViewHolder).tvTabe.setBackgroundResource(R.color.colorAccent)
}
override fun isLongPressDragEnabled(): Boolean {
//禁用默认拖动
return false
}
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {}
})
//赋予RecycleView滑动能力
itemTouchHelper.attachToRecyclerView(rv_table)
TableAdapter().let {
it.mTableList = tableList
rv_table.adapter = it
//将拖动职能传递给Adapter
it.mItemTouchHelper = itemTouchHelper
}
}
class TableAdapter : RecyclerView.Adapter<TableAdapter.TableViewHolder>(){
var mTableList = ArrayList<String>()
var mItemTouchHelper: ItemTouchHelper? = null
override fun getItemCount(): Int {
return mTableList.size
}
override fun onBindViewHolder(holder: TableViewHolder, position: Int) {
val table = mTableList[position]
holder.tvTabe.text = table
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TableViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.item_table, parent, false)
return TableViewHolder(view)
}
inner class TableViewHolder constructor(view: View): RecyclerView.ViewHolder(view) {
val tvTabe = view.findViewById<TextView>(R.id.tv_table)
init {
tvTabe.setOnLongClickListener {
if (this.adapterPosition != 0){
mItemTouchHelper?.startDrag(this)
return@setOnLongClickListener true
}
return@setOnLongClickListener false
}
}
}
}
场景二:只需将拖动的item和最终位置item进行交换,途径位置保持不变
1、在onMove()中将经过的位置记录到拖动的ViewHolder中
2、在clearView()中进行位置交换
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val tableList = ArrayList<String>()
for (i in 1..200) {
tableList.add("桌(${i})")
}
rv_table.layoutManager = GridLayoutManager(this, 5)
val itemTouchHelper = ItemTouchHelper(object : ItemTouchHelper.Callback() {
override fun getMovementFlags(
recyclerView: RecyclerView,
viewHolder: RecyclerView.ViewHolder
): Int {
//拖动方向
val dargFlags =
ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT or ItemTouchHelper.UP or ItemTouchHelper.DOWN
//滑动方向
val swipeFlags = ItemTouchHelper.UP or ItemTouchHelper.DOWN
//设置拖动、滑动方向
return makeMovementFlags(dargFlags, swipeFlags)
}
override fun onMove(
recyclerView: RecyclerView,
viewHolder: RecyclerView.ViewHolder,
target: RecyclerView.ViewHolder
): Boolean {
//经过的ViewHolder位置保存到拖动的ViewHolder中
val toPosition = target.adapterPosition
(viewHolder as TableAdapter.TableViewHolder).toPosition = toPosition
return true
}
override fun onSelectedChanged(viewHolder: RecyclerView.ViewHolder?, actionState: Int) {
super.onSelectedChanged(viewHolder, actionState)
//长按选中更新要拖动的ViewHolder背景色
(viewHolder as? TableAdapter.TableViewHolder)?.tvTabe?.setBackgroundResource(R.color.colorPrimary)
}
override fun clearView(
recyclerView: RecyclerView,
viewHolder: RecyclerView.ViewHolder
) {
super.clearView(recyclerView, viewHolder)
(viewHolder as TableAdapter.TableViewHolder).tvTabe.setBackgroundResource(R.color.colorAccent)
//拖动ViewHolder位置
val fromPosition = viewHolder.adapterPosition
//终点位置
val toPosition = viewHolder.toPosition
if (toPosition >= 0){
Collections.swap(tableList, fromPosition, toPosition)
recyclerView.adapter?.let{
it.notifyItemChanged(fromPosition)
it.notifyItemChanged(toPosition)
}
}
}
override fun isLongPressDragEnabled(): Boolean {
//禁用默认拖动
return false
}
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {}
})
//赋予RecycleView滑动能力
itemTouchHelper.attachToRecyclerView(rv_table)
TableAdapter().let {
it.mTableList = tableList
rv_table.adapter = it
//将拖动职能传递给Adapter
it.mItemTouchHelper = itemTouchHelper
}
}
class TableAdapter : RecyclerView.Adapter<TableAdapter.TableViewHolder>(){
var mTableList = ArrayList<String>()
var mItemTouchHelper: ItemTouchHelper? = null
override fun getItemCount(): Int {
return mTableList.size
}
override fun onBindViewHolder(holder: TableViewHolder, position: Int) {
val table = mTableList[position]
holder.tvTabe.text = table
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TableViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.item_table, parent, false)
return TableViewHolder(view)
}
inner class TableViewHolder constructor(view: View): RecyclerView.ViewHolder(view) {
val tvTabe = view.findViewById<TextView>(R.id.tv_table)
var toPosition = -1
init {
tvTabe.setOnLongClickListener {
if (this.adapterPosition != 0){
mItemTouchHelper?.startDrag(this)
return@setOnLongClickListener true
}
return@setOnLongClickListener false
}
}
}
}