美文网首页 移动 前端 Python Android Java
RecyclerView扩展篇-ItemTouchHelper

RecyclerView扩展篇-ItemTouchHelper

作者: dashingqi | 来源:发表于2020-09-03 09:44 被阅读0次
Android_Banner.jpg

简介

ItemToucherHelper
  • 它是一个工具类,用来实现RecyclerView中Item的滑动删除和拖拽移动
  • 实现效果


    rv_goof.gif
实现过程
定义一个类继承 ItemtouchHelper.Callback
  • 在ItemTouchHelper.Callback。中我们需要实现它的三个方法
    • getMovementFlags():该方法是用来告诉系统当我们拖拽或者滑动的时候我们的操作方向
    • onMove():该方法是用来移动Item交换位置的方法
    • onSwiped():该方法是用来滑动Item的方法,一般我们滑动就是将该条数据删除
    • 通常我们需要在定义一个接口类,将onMove和onSwiped两个方法的操作,通过回调的方式暴露给使用者。
  • 实现代码如下
class MyItemTouchHelperCallback(var touchHelperListener: MyItemTouchHelperCallbackListener) :
    ItemTouchHelper.Callback() {

    /**
     * 移动的标识
     * 就是当我们滑动或者拖拽的时候,需要我们告诉系统方向
     */
    override fun getMovementFlags(
        recyclerView: RecyclerView,
        viewHolder: RecyclerView.ViewHolder
    ): Int {
        val layoutManager = recyclerView.layoutManager
        //这里面针对LinearLayoutManger管理器的情况处理
        if (layoutManager is LinearLayoutManager) {
            val linearLayoutManager: LinearLayoutManager = layoutManager as LinearLayoutManager
            val orientation: Int = linearLayoutManager.getOrientation()

            /**
             * 拖拽的变量
             */
            var dragFlag = 0

            /**
             * 滑动的变量
             */
            var swipeFlag = 0

            // 为了方便理解,相当于分为横着的ListView和竖着的ListView
            // 如果是横向的布局
            if (orientation == LinearLayoutManager.HORIZONTAL) {
                swipeFlag = ItemTouchHelper.UP or ItemTouchHelper.DOWN
                dragFlag = ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT
            } else if (orientation == LinearLayoutManager.VERTICAL) {
                // 如果是竖向的布局
                dragFlag = ItemTouchHelper.UP or ItemTouchHelper.DOWN
                swipeFlag = ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT
            }
            //第一个参数是拖拽flag,第二个是滑动的flag
            return makeMovementFlags(dragFlag, swipeFlag)
        }
        return 0
    }

    /**
     * 移动
     */
    override fun onMove(
        recyclerView: RecyclerView,
        viewHolder: RecyclerView.ViewHolder,
        target: RecyclerView.ViewHolder
    ): Boolean {
        if (touchHelperListener != null)
            //参数一:当前我们移动的Item所处于Adapter中的position
            //参数二:我们要移动到的位置所处于Adapter中的position
            return touchHelperListener.onMove(viewHolder.adapterPosition, target.adapterPosition)
        return false
    }

    /**
     * 侧边滑动删除
     */
    override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
            if (touchHelperListener!=null){
                touchHelperListener.onSwiped(viewHolder.adapterPosition)
            }
    }

    /**
     * 回调事件
     */
    interface MyItemTouchHelperCallbackListener {
        fun onSwiped(adapterPosition: Int)
        fun onMove(currentPosition: Int, targetPosition: Int): Boolean
    }
}
Activity中,实现回调事件,将ItemTouchHelper于RecyclerView进行绑定
  • 代码实现如下
class PositionActivity : AppCompatActivity(),
    MyItemTouchHelperCallback.MyItemTouchHelperCallbackListener {
    val viewModel by lazy {
        ViewModelProvider(this)[PositionViewModel::class.java]
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val positionDataBinding = DataBindingUtil.setContentView<ActivityPositionBinding>(
            this,
            R.layout.activity_position
        )

        positionDataBinding.viewModel = viewModel
        //定义一个Callback
        val itemTouchHelperCall = MyItemTouchHelperCallback(this)
      // 将Callback传递到ItemTouchHelper中
        val itemTouchHelper = ItemTouchHelper(itemTouchHelperCall)
        // ItemTouchHelper与RecyclerView进行绑定
        itemTouchHelper.attachToRecyclerView(positionRv)
      }
//在这里处理滑动删除的逻辑
    override fun onSwiped(adapterPosition: Int) {
        if (viewModel.items.isNotEmpty()) {
            viewModel.items.removeAt(adapterPosition)
            positionRv.adapter?.notifyItemRemoved(adapterPosition)
        }
    }

    //在这里处理移动
    override fun onMove(currentPosition: Int, targetPosition: Int): Boolean {
        if (viewModel.items.isNotEmpty()) {
            // 交换位置
            Collections.swap(viewModel.items, currentPosition, targetPosition)
            // 通知数据变化,同时给一个动画
            positionRv.adapter?.notifyItemMoved(currentPosition, targetPosition)
            return true
        }
        return false
    }
}
  • 以上两个过程就是主要实现该效果的核心代码,由于本文使用了DataBinding+ViewModel+binding-collection-adapter,这里也贴一下ViewModel和actiivty的xml文件代码
  • ViewModel中的代码
class PositionViewModel : ViewModel() {
    private var imgUrls = mutableListOf(
        "https://img.fulaishiji.com/images/goods/19883/big/03957c4d-6869-4cef-ad3e-824852f9da2b_800x800.png",
        "https://img.fulaishiji.com/images/goods/19307/big/e2635d9a-d5eb-4acf-b08c-44483a8554e2_800x800.jpg",
        "https://img.fulaishiji.com/images/goods/17249/big/3389ee28-5b14-4b55-8f5d-64a00d5deb37_800x800.jpg",
        "https://img.fulaishiji.com/images/goods/12461/big/b0be6cbd-3164-470b-b355-d9b41b0ce0e6_800x800.jpg",
        "https://img.fulaishiji.com/images/goods/16743/big/65843bf9-7ba1-48d0-884e-aefeebf9b635_964x964.jpg",
        "https://img.fulaishiji.com/images/goods/12534/big/3dabd1b5-f37f-4320-9832-fccbdc8e1ecf_800x800.jpg",
        "https://img.fulaishiji.com/images/goods/14897/big/e1c774c9-7003-4a4a-9e12-1bdf1d729457_800x800.jpg",
        "https://img.fulaishiji.com/images/goods/12753/middle/95f064c5-8bfc-44d6-a7d8-5058cb3f93e7_800x800.jpg",
        "https://img.fulaishiji.com/images/goods/10396/middle/e174305c-b32c-4b9d-a0b1-a14de0ae011a_3648x3648.jpg",
        "https://img.fulaishiji.com/images/goods/17824/middle/19d6253c-1ef9-48f0-b63f-d01d2f354eee_2728x2728.jpg",
        "https://img.fulaishiji.com/images/goods/17337/middle/9974521a-34c4-4daf-9c07-717dface9cce_800x800.jpg",
        "https://img.fulaishiji.com/images/goods/13223/middle/a0a32982-3af5-45ae-9252-a554503ec829_800x800.jpg",
        "https://img.fulaishiji.com/images/goods/19906/middle/41dca304-69b2-490f-b001-0b99fa4fcc60_1008x1008.jpg",
        "https://img.fulaishiji.com/images/goods/19653/middle/c31cca8b-7468-4d5f-a06c-8427a7d01656_800x800.jpg"
    )

    val items = ArrayList<Food>()
    val itemBinding = ItemBinding.of<Food>(BR.item, R.layout.rv_item)

    init {
        for (index in 0 until 200) {
            val food = Food()
            food.name = "name $index"
            food.desc = "desc $index"
            val position = (Math.random() * (imgUrls.size - 1)).toInt()
            food.imgUrl = imgUrls[position]
            items.add(food)
        }
    }
}
  • activity中xml文件
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">

    <data>

        <variable
            name="viewModel"
            type="com.dashingqi.module.recyclerview.PositionViewModel" />

    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".PositionActivity">

        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/positionRv"
            itemBinding="@{viewModel.itemBinding}"
            items="@{viewModel.items}"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

相关文章

网友评论

    本文标题:RecyclerView扩展篇-ItemTouchHelper

    本文链接:https://www.haomeiwen.com/subject/jvggsktx.html