首页 > 解决方案 > 带有 LayoutBinding 的 RecyclerView - 滑动以删除 - 留下项目大小的空白空间

问题描述

我在网上搜索了很多,但显然无法找到答案。我有一个待办事项列表,并且适配器附加了滑动功能,因此当有人滑动项目时,它会从列表中删除该项目。

问题是被删除的项目被新项目替换,但该区域显示为空白区域。

在此处输入图像描述

我知道那里有行项目但没有显示,如果我关闭应用程序并再次打开它会显示。

这是我的适配器类。

@Suppress("NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS")
class TodoAdapter(var allTodos: ArrayList<Todo>, var callback: iTodoAdapter)
: RecyclerView.Adapter<TodoAdapter.TodoViewHolder>(),
ItemTouchHelperCustomListener {

//Hello
override fun onItemDismiss(position: Int) {
    callback.onDelete(position)
}

override fun onItemMove(fromPosition: Int, toPosition: Int) : Boolean {
    callback.onItemsSwapped(fromPosition, toPosition)
    return true
}

override fun updateDatabasePositions(fromPosition: Int, toPosition: Int) {
    val size = allTodos.size - 1
    for (index in 0..size) {
        allTodos.get(index).position = index
    }
    callback.onPositionsUpdated()
}


override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) : TodoViewHolder {
    val binding = LayoutTodoItemBinding.inflate(LayoutInflater.from(parent.context), parent, false)
    return TodoViewHolder(binding)
}

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

private fun createOnClickListener(position: Int) : View.OnClickListener {
    return View.OnClickListener {
        val checked = (it as CheckBox).isChecked
        allTodos.get(position).isSelected = checked
        allTodos.get(position).let { callback.onItemUpdated(it) }
    }
}


override fun onBindViewHolder(holder: TodoViewHolder, position: Int) {
    holder.bind(allTodos.get(position), createOnClickListener(position))
}

//We only have 1 type of item
override fun getItemViewType(position: Int): Int {
    return position
}

class TodoViewHolder(private val binding : LayoutTodoItemBinding) :
    RecyclerView.ViewHolder(binding.root) {

    fun bind(todoItem : Todo?, clickListner: View.OnClickListener) {
        binding.apply {
            setTodoItem(todoItem)
            onClickListener = clickListner
            executePendingBindings()
        }
    }
}

fun getData() : ArrayList<Todo> {
    return this.allTodos
}


interface iTodoAdapter {
    fun onDelete(position: Int)
    fun onItemsSwapped(from: Int, to: Int)
    fun onPositionsUpdated()
    fun onItemUpdated(item: Todo)
}
}

这是我的片段中实现的 iTodoAdapter

override fun onDelete(position: Int) {
    viewModel.delete(allTodos.get(position))
}

override fun onItemsSwapped(from: Int, to: Int) {
    Collections.swap(allTodos, from, to)
    rcyTodo?.adapter?.notifyDataSetChanged()
}

override fun onPositionsUpdated() {
    viewModel.updateAll((rcyTodo?.adapter as TodoAdapter).getData())
}

override fun onItemUpdated(item: Todo) {
    viewModel.update(item)
}

这是我的片段设置:

    val dividerItemDecoration = DividerItemDecoration(rcyTodo.context,DividerItemDecoration.VERTICAL)
    rcyTodo.addItemDecoration(dividerItemDecoration)

    rcyTodo.apply {
        adapter = TodoAdapter(allTodos, this@Todo)
        setHasFixedSize(true)
    }

    setupSwipeToDelete()
    setCurrentItems()

这里是函数

private fun setupSwipeToDelete() {
    val itemTouchHelperCallback = ItemTouchHelperCallback(rcyTodo.adapter as TodoAdapter)
    val itemTouchHelper = ItemTouchHelper(itemTouchHelperCallback)
    itemTouchHelper.attachToRecyclerView(rcyTodo)
}

@SuppressLint("CheckResult")
private fun setCurrentItems() {
    viewModel.getAllTodos().subscribe({
        allTodos.clear()
        allTodos.addAll(it)
        rcyTodo?.recycledViewPool?.clear()
        rcyTodo?.adapter?.notifyDataSetChanged()
    }, {

    })
}

我在某处发现清理池 (rcyTodo?.recycledViewPool?.clear()) 应该重绘项目但不起作用。

我在想我是否必须删除布局绑定并以简单的方式进行?有办法解决吗?我错过了什么吗?顺便说一句,空白空间确实有项目,这只发生在我滑动后删除一个项目时。与绘图元素有关,不知何故回收者视图认为这个位置应该是空的。

标签: androidkotlinandroid-recyclerview

解决方案


使用您的notifyDataSetChanged,在适配器上再调用一个功能 - notifyItemRemoved(position)。文档说:

通知任何已注册的观察者,先前位于该位置的项目已从数据集中删除。现在可以在 oldPosition - 1 找到以前位于 position 和之后的项目。

希望它成功:-)


推荐阅读