插入新项目时,RecyclerView不会在顶部滚动

时间:2020-05-16 12:19:21

标签: android android-recyclerview linearlayoutmanager

我有一个RecyclerView,它允许滑动删除功能。定义后,将显示Snackbar,以确认删除操作,并允许用户“撤消”删除操作。

一切正常,直到我删除位置0的项目,然后按undo。该项目将重新插入列表,但用户需要向上滚动以使其重新显示。

我尝试过的

  • 在RecyclerView上设置recyclerView.isNestedScrollingEnabled"

  • 在协调器布局上使用layoutCoordinator.scrollTo(0, 0)

  • 在RecyclerView上使用recyclerView.smoothScrollToPosition(0)

  • 在RecyclerView上使用recyclerView.scrollToPosition(0)

  • 在RecyclerView上使用recyclerView.scrollTo(0, 0)

  • 在适配器上使用itemAdapter.notifiyItemInserted(0)

  • 在适配器上使用itemAdapter.notifiyItemchanged(0)

  • 在适配器上使用itemAdapter.notifyDataSetChanged()

  • 使用layoutManager.scrollToPositionWithOffset(0, 0) LayoutManager

  • 创建自定义LayoutManager并覆盖 smoothScrollToPosotion()和我自己的实现。

以上均未提供解决方案。


下面是工作原理。

ItemsFragment

onCreateView内部-这是在设置itemAdapterrecyclerView

    val itemAdapter = object : ItemRecyclerViewAdapter() {
        override fun onItemClicked(item: Item) {
            // todo
        }
    }

    val layoutManager = LinearLayoutManager(context)
    recyclerView.layoutManager = layoutManager
    recyclerView.adapter = itemAdapter

这是我的swipeToDeleteCallbackSnackbar动作,用于“撤消”删除操作:

val swipeToDeleteCallback = object : SwipeToDeleteCallback() {
        override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
            val position = viewHolder.adapterPosition
            val item = itemAdapter.currentList[position]
            viewModel.deleteItem(item)

            val snackBar = Snackbar.make(
                recyclerView,
                getString(R.string.snackbar_msg_deleted_card),
                Snackbar.LENGTH_LONG
            )
            snackBar.setAction(R.string.snack_bar_undo) {
                viewModel.restoreItem(item)
                recyclerView.smoothScrollToPosition(position)
            }
            snackBar.show()
        }
    }
val itemTouchHelper = ItemTouchHelper(swipeToDeleteCallback)
itemTouchHelper.attachToRecyclerView(recyclerView)

设置从ViewModel观察到的LiveData项目。更改将立即传递给适配器:

val items = viewModel.items.await()
    items.observe(viewLifecycleOwner, Observer {
        it?.let {
            itemAdapter.setItems(it)
        }
    })

ItemsAdapter

使用DiffUtilCallback提交列表:

fun setItems(list: List<Item>?) {
    adapterScope.launch {
        val itemsList = when(list) {
            null -> emptyList()
            else -> list.sortedByDescending {
                it.itemId
            }
        }
        withContext(Dispatchers.Main) {
            submitList(itemsList)
        }
    }
}

临时修复

到目前为止,唯一起作用的是我的Snackbar动作中的这种骇人听闻的解决方案:

snackBar.setAction(R.string.snack_bar_undo) {
                viewModel.restoreItem(item)
                if (position == 0) {
                    itemsAdapter.notifyItemInserted(0)
                    recyclerView.smoothScrollToPosition(0)
                }
            }

在这里,我正在检查项目position是否为0。如果是这样,则告诉适配器在item处插入了新的position 0-然后开始滚动。否则,请勿执行任何操作,因为position以外的0上的任何项目都将插入并制作动画,因为DiffUtilCallback

此临时修复程序有效,但滚动为“快照”,并在日志中产生错误:

RecyclerView:平滑滚动时越过目标位置

此外,此解决方案无法100%地起作用。大约有60%的时间。

有人知道我找不到更好的解决方案/东西以及解决上述错误的方法吗?

0 个答案:

没有答案