ItemTouchHelper onMove Обновить позиции элементов - PullRequest
1 голос
/ 05 апреля 2020

При использовании метода itemTouchHelper onMove. Как вы можете при использовании нумерованного списка на основе позиции в списке.

Например, пункт 1, пункт 2, пункт 3 и т. Д. c. все основано на фактической позиции в списке, в котором находится элемент. Как это сделать при перемещении элемента путем перетаскивания его вверх или вниз. Обновите остальные элементы в списке, чтобы отразить правильную позицию в списке, в котором он находится?

Я использую следующий код:

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
        }

Фрагмент:

enter image description here

Видео:

enter image description here

ОБНОВЛЕНИЕ (код адаптера):

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

ИСПЫТАТЕЛЬНЫЕ ДАННЫЕ

1 Ответ

1 голос
/ 06 апреля 2020

Единственный способ добиться этого - привязать ваши ViewHolder s, чтобы их TextView s отображали измененные позиции. Но вызов notifyDataSetChanged() или notifyItemRangeChanged(0, pos) приведет к тому, что все ваши элементы исчезнут и исчезнут, так как все они были повторно привязаны, я бы не рекомендовал это, поскольку это довольно уродливо (но все же, это будет работать )

Вы когда-нибудь использовали метод onBindViewHolder(holder: ViewHolder, position: Int, payloads: MutableList<Any>)? Это позволяет обновить только некоторые View внутри вашего ViewHolder без перерисовки всего 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}"
        }
    }

update

Вы уверены, что звоните notifyItemRangeChanged(min(fromPos, toPos), max(fromPos,toPos)? Эта вещь будет вызывать onBindViewHolder для каждого предмета в диапазоне. Вам следует позвонить после того, как вы позвоните notifyItemMoved. Когда он работает, попробуйте передать объект в качестве полезной нагрузки.

Журналы не показывают поведение, похоже, это вывод, когда адаптер связывает представления после инициализации.

...