如何禁用更新项目时发生的 RecyclerView (ListAdapter) 的自动滚动?

问题描述

背景

我有一个用户界面,显示用户全名列表,每个项目都有一个喜欢/不喜欢按钮。我正在使用一个 ListAdapter,它在底层使用 DiffUtilAsyncListDiffer API。用户列表作为来自 Room 数据库的 LiveData 接收,并按“isLiked”排序。

问题

每当点击“赞”按钮时,我使用 LiveData 时的 Room 都会将新数据重新提交给适配器。问题是,由于列表是按“isLiked”排序的,喜欢的用户会改变它的位置,而 RecyclerView 将始终滚动到新位置。

我不想看到更新项的新位置。那么,如何禁用自动滚动行为?

我尝试了什么

MainActivity.kt

    ..
    val userAdapter = UsersAdapter(this)
    val ll = LinearLayoutManager(this,LinearLayoutManager.VERTICAL,false)
   
    recyclerView.apply {
        layoutManager = ll
        adapter = userAdapter
        itemAnimator = null
        setHasFixedSize(true)
    }
    
    viewModel.users.observe(this,{
        // This will force the recycler view to scroll back to the previous position
        // But it's more of a workaround than a clean solution.
        val pos = ll.findFirstVisibleItemPosition()
        userAdapter.submitList(it) {
            recyclerView.scrollToPosition(pos)
        }
    })
    ..

UsersAdapter.kt

class UsersAdapter(
    private val clickListener: UserClickListener
) : ListAdapter<UserEntity,UsersAdapter.UserViewHolder>(DIFF_CALLBACK) {

    override fun onCreateViewHolder(parent: ViewGroup,viewType: Int): UserViewHolder {
        val view = LayoutInflater.from(parent.context).inflate(R.layout.item_user,parent,false)
        return UserViewHolder(view)
    }

    override fun onBindViewHolder(holder: UserViewHolder,position: Int) {
        val userEntity = getItem(position)
        holder.bind(userEntity,clickListener)
    }

    class UserViewHolder(view: View) : RecyclerView.ViewHolder(view) {
        private val textView: TextView = view.findViewById(R.id.fullName)
        private val fav: ImageButton = view.findViewById(R.id.fav)

        fun bind(user: UserEntity,clickListener: UserClickListener) {
            textView.text = user.fullName

            val favResId = if (user.favorite) R.drawable.like else R.drawable.dislike
            fav.setImageResource(favResId)

            fav.setOnClickListener {
                val newFav = !user.favorite
                val newFavResId = if (newFav) R.drawable.like else R.drawable.dislike
                fav.setImageResource(newFavResId)
                clickListener.onUserClicked(user,newFav)
            }
        }
    }

    interface UserClickListener {
        fun onUserClicked(user: UserEntity,isFavorite: Boolean)
    }

    companion object {
        private val DIFF_CALLBACK = object : DiffUtil.ItemCallback<UserEntity>() {
            override fun areItemsTheSame(
                oldUser: UserEntity,newUser: UserEntity
            ) = oldUser.id == newUser.id

            override fun areContentsTheSame(
                oldUser: UserEntity,newUser: UserEntity
            ) = oldUser.fullName == newUser.fullName && oldUser.favorite == newUser.favorite
        }
    }
}

我尝试使用常规 RecyclerView 适配器和 DiffUtil,并将检测移动设置为 false。
我也添加了 AsyncListDiffer。
我尝试了 ListAdapter,甚至尝试了分页库并使用了 PagedListAdapter。
DiffUtil 的回调更改了自动滚动,但我无法获得所需的行为。

非常感谢任何帮助!

解决方法

发生这种情况是因为您正在更新 VH 状态,也许您可​​以在“提交列表”调用之前删除用户喜欢的 VH。

MainActivity.kt

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        ...
        viewModel.users.observe(this,{ userAdapter.submitList(it) }
    }
    
    ...

    override fun onViewHolderClick(model: UserEntity) {
        userAdapter.removeItem(model)
        viewModel.updateItem(model)
    }

并在您的适配器中添加此功能

UsersAdapter.kt

...
    fun removeItem(model: UserEntity) {
        val currentListCopy = mutableListOf<UserEntity>().apply { addAll(currentList) }
        currentListCopy.remove(model)
        submitList(currentListCopy)
    }
...

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...