Android kotlin 重新排序 recyclerview,在项目被持有时使用 ItemTouchHelper 调用函数

问题描述 投票:0回答:3

我有一个回收器视图,它的列表存储在firestore中。我想允许用户使用拖放功能对项目重新排序。当用户删除保持(放下项目)时,我想调用该函数来更新 firestore,但是只要位置发生更改,即使拖动到所需位置,该函数也会被调用。如何仅在放置项目时调用该函数。

val itemTouchHelper = ItemTouchHelper(
        object: ItemTouchHelper.SimpleCallback(ItemTouchHelper.UP or ItemTouchHelper.DOWN, 0){
            override fun onMove(
                recyclerView: RecyclerView,
                source: RecyclerView.ViewHolder,
                target: RecyclerView.ViewHolder
            ): Boolean {
                val sourcePosition = source.adapterPosition
                val targetPosition = target.adapterPosition

                Collections.swap(itemList, sourcePosition, targetPosition)
                adapter.notifyItemMoved(sourcePosition, targetPosition)

// Firestore update
                updateFirestoreList()

                return true
            }

            override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
                TODO("Not yet implemented")
            }
        })
android firebase kotlin android-recyclerview
3个回答
1
投票

当您选择拖动时,存储此位置

var sourcePosition = -1
override fun onSelectedChanged(viewHolder: RecyclerView.ViewHolder?, actionState: Int) {
     super.onSelectedChanged(viewHolder, actionState)
     if(actionState != ItemTouchHelper.ACTION_STATE_IDLE){
           sourcePosition = viewHolder!!.adapterPosition
     }
}

当你放下

clearView
时会被调用,获取ViewHolder的位置并交换Collection

override fun clearView(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder) {
    super.clearView(recyclerView, viewHolder)
    val targetPosition = viewHolder.adapterPosition
    if(sourcePosition != -1 && sourcePosition != targetPosition){
        Collections.swap(itemList, sourcePosition, targetPosition)
    }
    sourcePosition = -1
}

我希望它有帮助:))


1
投票

我实现它的方法是重写

clearView()
ItemTouchHelper
方法,并从中调用回调。它会像下面这样:

class MyTouchHelper(val onActionEnded: () -> Unit) : ItemTouchHelper.SimpleCallback(UP or DOWN, 0) {

    override fun onMove(
        recyclerView: RecyclerView,
        viewHolder: RecyclerView.ViewHolder,
        target: RecyclerView.ViewHolder,
    ): Boolean {
        recyclerView.adapter?.let { adapter ->
            adapter as MyListAdapter
            val from = viewHolder.absoluteAdapterPosition
            val to = target.absoluteAdapterPosition
            adapter.onItemMoved(from, to)
            return true
        }
        return false
    }

    override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {}

    override fun clearView(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder) {
        super.clearView(recyclerView, viewHolder)
        onActionEnded()
    }
}

onItemMovied(from, to)
MyListAdapter
类中的一个函数,其实现如下:

fun onItemMoved(from: Int, to: Int) {
    val list = currentList.toMutableList()
    list.add(to, list.removeAt(from))
    submitList(list)
}

它只是用新项目的位置更新列表(您可能有不同的方法,请根据您的需要随意使用它或根本不使用它)。@viethoang更新列表本身的实现似乎更高效。我建议尝试一下。

最后,在附加

MyTouchHelper
的地方,您可以使用它的回调来调用您的特定函数,如下所示:

ItemTouchHelper(MyTouchHelper {
    updateFirestoreList()// Or any other functions that you want.
}).attachToRecyclerView(recyclerView)

希望有帮助。


0
投票

您可以使用这个

ItemMoveCallback
来实现这一点。

class ItemMoveCallback(var mAdapter: ItemTouchHelperContract) : ItemTouchHelper.Callback() {
    override fun isLongPressDragEnabled(): Boolean {
        return false
    }

    override fun isItemViewSwipeEnabled(): Boolean {
        return false
    }

    override fun onSwiped(viewHolder: RecyclerView.ViewHolder, i: Int) {}

    override fun getMovementFlags(
        recyclerView: RecyclerView,
        viewHolder: RecyclerView.ViewHolder
    ): Int {
        val dragFlags = ItemTouchHelper.UP or ItemTouchHelper.DOWN
        return makeMovementFlags(dragFlags, ItemTouchHelper.ACTION_STATE_IDLE)
    }

    override fun onMove(
        recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder,
        target: RecyclerView.ViewHolder
    ): Boolean {
        mAdapter.onRowMoved(viewHolder.adapterPosition, target.adapterPosition)
        return true
    }

    override fun onSelectedChanged(
        viewHolder: RecyclerView.ViewHolder?,
        actionState: Int
    ) {
        if (actionState != ItemTouchHelper.ACTION_STATE_IDLE) {
            if (viewHolder is RecyclerView.ViewHolder) {
                val myViewHolder: RecyclerView.ViewHolder = viewHolder
                mAdapter.onRowSelected(myViewHolder)
            }
        }
        super.onSelectedChanged(viewHolder, actionState)
    }

    override fun clearView(
        recyclerView: RecyclerView,
        viewHolder: RecyclerView.ViewHolder
    ) {
        super.clearView(recyclerView, viewHolder)
        val myViewHolder: RecyclerView.ViewHolder = viewHolder
        mAdapter.onRowClear(myViewHolder)
    }

    interface ItemTouchHelperContract {
        fun onRowMoved(fromPosition: Int, toPosition: Int)
        fun onRowSelected(myViewHolder: RecyclerView.ViewHolder?)
        fun onRowClear(myViewHolder: RecyclerView.ViewHolder?)
    }
}

现在,在您的 recyclerview 适配器中,

class MYAdapter : RecyclerView.Adapter<VH>, ItemMoveCallback.ItemTouchHelperContract {

.........
.........

override fun onRowMoved(fromPosition: Int, toPosition: Int) {
        if (fromPosition < toPosition) {
            for (i in fromPosition until toPosition) {
                Collections.swap(itemsList, i, i + 1)
            }
        } else {
            for (i in fromPosition downTo toPosition + 1) {
                Collections.swap(itemsList, i, i - 1)
            }
        }
        notifyItemMoved(fromPosition, toPosition)
    }

    override fun onRowSelected(myViewHolder: RecyclerView.ViewHolder?) {
        binding.root.setBackgroundColor(Color.GRAY)
        // Apply the logic of notifying the user that item is selected here.
    }

    override fun onRowClear(myViewHolder: RecyclerView.ViewHolder?) {
        binding.root.setBackgroundColor(Color.TRANSPARENT)
        yourListenerToUpdateData?.onDataReordered(itemsList)
    }

}
© www.soinside.com 2019 - 2024. All rights reserved.