首页 > 解决方案 > ItemTouchHelper onMove 更新物品位置

问题描述

使用 itemTouchHelper onMove 方法时。如何根据列表中的位置使用编号列表。

例如,第 1 项、第 2 项、第 3 项等都基于该项目在列表中的实际位置。然后如何通过向上或向下拖动来移动项目。更新列表中的其余项目以反映其在列表中的正确位置?

我正在使用以下代码:

override fun onMove(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder): Boolean {

            val fromPosition = viewHolder.adapterPosition
            val toPosition = target.adapterPosition

            Collections.swap(steps!!, fromPosition, toPosition)

            recyclerView.adapter!!.notifyItemMoved(fromPosition,toPosition)

            return true
        }

片段:

在此处输入图像描述

视频:

在此处输入图像描述

更新(适配器代码):

val TAG:String = "StepAdapter"
var steps: MutableList<Step> = ArrayList()

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): StepViewHolder {
    return StepViewHolder(
        LayoutInflater.from(parent.context)
            .inflate(R.layout.recipe_property_step_list_item, parent, false))
}

override fun getItemCount(): Int{
    return steps.size
}

override fun onBindViewHolder(holder: StepViewHolder, position: Int) {
    holder.bind(steps.get(position), position)
    Log.i(TAG,"onBindViewHolder - ${steps.get(position)}")
}

override fun onBindViewHolder(holder: StepViewHolder, position: Int, payloads: MutableList<Any>) {
    Log.i(TAG,"onBindViewHolder - Payloads - $payloads")
    val text:String = StringBuilder("${position + 1}.) ${steps[position].text}").toString()
    Log.i(TAG,"onBindViewHolder - Text - $text")
    holder.st_text.text = text
}

fun updateSteps(newSteps: MutableList<Step>){
    val diffResult = DiffUtil.calculateDiff(StepDiffCallBack(this.steps,newSteps))
    this.steps.clear()
    this.steps.addAll(newSteps)
    notifyDataSetChanged()
    diffResult.dispatchUpdatesTo(this)
}

日志:

2020-04-12 16:57:21.787 15808-15808/com.keep.recipeapp I/StepAdapter: onBindViewHolder - Payloads - []
2020-04-12 16:57:21.787 15808-15808/com.keep.recipeapp I/StepAdapter: onBindViewHolder - Text - 1.) Prepping the kitchen sink
2020-04-12 16:57:21.789 15808-15808/com.keep.recipeapp I/StepAdapter: onBindViewHolder - Payloads - []
2020-04-12 16:57:21.789 15808-15808/com.keep.recipeapp I/StepAdapter: onBindViewHolder - Text - 2.) prep the nuts and bolts
2020-04-12 16:57:21.791 15808-15808/com.keep.recipeapp I/StepAdapter: onBindViewHolder - Payloads - []
2020-04-12 16:57:21.791 15808-15808/com.keep.recipeapp I/StepAdapter: onBindViewHolder - Text - 3.) Cook the kitchen sink

测试数据

标签: androidkotlinandroid-recyclerviewitemtouchhelper

解决方案


实现这一点的唯一方法是重新绑定您ViewHolder的 s 以便他们TextView的 s 显示更改的位置。但是调用notifyDataSetChanged()ornotifyItemRangeChanged(0, pos)会让你所有的物品淡出淡入,因为它们都被重新绑定了,我不建议这样做,因为它非常丑陋(但它仍然可以工作

你用过方法onBindViewHolder(holder: ViewHolder, position: Int, payloads: MutableList<Any>)吗?这允许仅更新View您内部的一些 sViewHolder而无需重新绘制整个s View,因此您的更改RecyclerView将更加平滑。

在您的onMove方法中,您调用notifyItemRangeChanged提供应该更新的项目的范围,并提供 Any() 作为有效负载,因为重新绑定视图不需要额外的信息,因为您可以在适配器的方法中访问位置和数据。

    override fun onMove(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder): Boolean {
        val fromPosition = viewHolder.adapterPosition
        val toPosition = target.adapterPosition
        Collections.swap(steps!!, fromPosition, toPosition)

        recyclerView.adapter!!.notifyItemMoved(fromPosition,toPosition)
        recyclerView.adapter!!.notifyItemRangeChanged(0, max(fromPosition, toPosition), Any())
        // as you dont need to change items that are below the maximum positions
        // their positions will be correct
        return true
    }

请记住,super如果有效负载为空,您应该调用方法。

    override fun onBindViewHolder(holder: MyViewHolder, position: Int, payloads: MutableList<Any>) {
        if (payloads.isEmpty()) super.onBindViewHolder(holder, position, payloads)
        else {
            holder.theTextView.text = "$position.)${myList[position].data}"
        }
    }

更新

你确定你打电话notifyItemRangeChanged(min(fromPos, toPos), max(fromPos,toPos)?这件事将要求onBindViewHolder范围内的每个项目。您应该在调用后调用它notifyItemMoved。当它工作时,尝试将对象作为有效负载传递。

日志不显示行为,它似乎是适配器在初始化后绑定视图时的输出。


推荐阅读