PagedListAdapter и ItemTouchHelper с комнатой - как вы обновляете во время onMove () - PullRequest
3 голосов
/ 03 июля 2019

У меня проблема в том, что при перетаскивании элемента на мой RecyclerView обратный вызов onMove() не может изменить фактический порядок массива элементов, поскольку этот массив управляется PagedListAdapter. Если я делаю это на БД, это происходит в фоновом потоке, потому что Room требует, чтобы я это сделал (и я действительно должен в любом случае делать БД в фоновом потоке), и, как вы можете себе представить, это плохо работает с перетаскивание элемента.

Мое понимание того, как работает ItemTouchHelper, заключается в том, что на onMove() я должен переставить все, что хочу, чтобы его визуально отображали, и затем я могу сохранить в БД на clearView(). Но я не могу переставить на onMove().

Это упрощение моего текущего кода, который работает, но визуальные подсказки перетаскивания не работают хорошо.

inner class SwipeCallback() : ItemTouchHelper.SimpleCallback(ItemTouchHelper.UP or ItemTouchHelper.DOWN, ItemTouchHelper.RIGHT) {
        override fun onMove(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder): Boolean {
            val item1 = getItem(viewHolder.adapterPosition)
            val item2 = getItem(target.adapterPosition)
            if (item1 != null && item2 != null) {
                //BASICALLY JUST SWAPPING THE TWO POSITIONS ON THE OBJECTS but not doing anything with the adapter array because the PagedListAdapter doesn't allow me to modify the array as far I know.
                swapItems(item1,item2)

                }
                return true
            }
            return false
        }

        override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
            TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
        }

        override fun isLongPressDragEnabled(): Boolean {
            return false
        }

        override fun onSelectedChanged(viewHolder: RecyclerView.ViewHolder?, actionState: Int) {
            super.onSelectedChanged(viewHolder, actionState)
            if (actionState == ACTION_STATE_DRAG) {
                viewHolder?.itemView?.alpha = 0.5f
            }
        }

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

            viewHolder?.itemView?.alpha = 1.0f

            //THIS IS WHERE I UPDATED THE DB, currentList is the PagedListAdapter array. This is an inner class of my PagedListAdapter.
            currentList?.let {updateList(it) }
        }
    }

Так как я могу заставить это работать визуально?

Спасибо.

1 Ответ

0 голосов
/ 15 июля 2019

Обновление : Я создал здесь пример

Я предполагаю, что вы используете Room Database для загрузки данных подкачки в пользовательский интерфейс.Фактически, если вы используете библиотеку Pagination, это единственный способ сделать наш список способным реагировать на динамическое изменение данных.

В адаптере вам просто нужно уведомить базу данных об изменении в функции onMove ()

    class SwipeCallback(
        private val adapter: HomeSpotAdapter,
        private val onItemMove: (from: Int, to: Int) -> Unit
    ) : ItemTouchHelper.SimpleCallback(ItemTouchHelper.UP or ItemTouchHelper.DOWN, ItemTouchHelper.RIGHT) {

        override fun onMove(
            recyclerView: RecyclerView,
            viewHolder: RecyclerView.ViewHolder,
            target: RecyclerView.ViewHolder
        ): Boolean {
            val from = viewHolder.adapterPosition
            val to = target.adapterPosition
            val item1 = adapter.getItem(from)
            val item2 = adapter.getItem(to)
            if (item1 != null && item2 != null) {

                // Notify database to swap items here
                onItemMove(from, to)

                return true
            }
            return false
        }

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

        override fun isLongPressDragEnabled(): Boolean {

            // It has to be true
            return true
        }

        override fun onSelectedChanged(viewHolder: RecyclerView.ViewHolder?, actionState: Int) {
            super.onSelectedChanged(viewHolder, actionState)
            if (actionState == ACTION_STATE_DRAG) {
                viewHolder?.itemView?.alpha = 0.5f
            }
        }

        override fun clearView(recyclerView: RecyclerView,
                               viewHolder: RecyclerView.ViewHolder) {
            super.clearView(recyclerView, viewHolder)
            viewHolder.itemView.alpha = 1.0f

            // Don't need to do anything here
        }
    }

Во фрагменте мы передаем лямбда-функцию onItemMove адаптеру

        ItemTouchHelper(HomeSpotAdapter.SwipeCallback(adapter) { from, to ->
            viewModel.swapItems(from, to)
        }).apply {
            attachToRecyclerView(recyclerView.getRecycler())
        }

Для обмена элементами в БД, в основном, мы можем использовать функцию swapItems (), подобную этой

    fun swapItem(from: Int, to: Int) {

        // I'm using executor to run query in worker thread here, but you can choose whatever you want

        Executors.newSingleThreadExecutor().execute {

            val item1 = db.HomeSpotDao().getSpot(from)
            val item2 = db.HomeSpotDao().getSpot(to)

            // Swap index of 2 items

            val newItem1 = item1.copy()
            newItem1.indexInResponse = item2.indexInResponse

            val newItem2 = item2.copy()
            newItem2.indexInResponse = item1.indexInResponse

            db.HomeSpotDao().updateSpot(newItem1)
            db.HomeSpotDao().updateSpot(newItem2)
        }
    }

Вы можете взглянуть на этот класс в Google Sample, чтобы понять, как indexInResponse используется для отслеживания индекса элементов в списке

Ссылка примера Google здесь

...