【发布时间】:2021-02-09 21:49:47
【问题描述】:
背景
我有一个 UI 显示用户全名列表,每个项目都有一个喜欢/不喜欢按钮。我正在使用ListAdapter,它在后台使用DiffUtil 和AsyncListDiffer API。用户列表以 LiveData 的形式从 Room 数据库接收,它按“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 的回调更改了自动滚动,但我无法获得所需的行为。
非常感谢任何帮助!
【问题讨论】:
-
当用户在 viewHolder 上按“like”时 UI 会发生变化吗?也许您可以在列表出现时仅获取列表项,而不是在每个“喜欢”时刷新它。如果您需要在用户点击“喜欢”按钮时更改 viewHolder,您需要使用 notifyDataSetChanged(如果您不想看到闪烁)并且还保留 Room 上的更改,但在发生这种情况时不使用“submitlist”更新列表。 ListAdapter 是一种使用 diff util 的绝佳而简单的方法,但如果您需要更新 viewHolder 的一部分,您总是会看到标志性的闪烁。
-
我遇到的问题是更新项目时发生的自动滚动。另外,我必须重新提交数据,因为它是一个有序列表。
-
嗯,这是因为您正在更新 VH 状态,也许您可以在“submitlist”调用之前删除用户喜欢的 VH
标签: android android-recyclerview android-paging android-diffutils android-listadapter