我目前有一个回收视图,其中的数据每5秒更新一次。为了更新列表上的数据,我正在使用
notifyItemChanged(position);
notifyItemRangeChanged(position, mList.size());
每次调用notifyItemChanged()时,我的回收站视图上的项目会正确更新,但是它会闪烁,因为这会导致onBindViewHolder再次被调用。所以每次都像是新加载一样。如果可能的话,我该如何防止这种情况发生?我目前有一个回收视图,其中的数据每5秒更新一次。为了更新列表上的数据,我正在使用
notifyItemChanged(position);
notifyItemRangeChanged(position, mList.size());
每次调用notifyItemChanged()时,我的回收站视图上的项目会正确更新,但是它会闪烁,因为这会导致onBindViewHolder再次被调用。所以每次都像是新加载一样。如果可能的话,我该如何防止这种情况发生?RecyclerView内置了动画效果,通常会增加不错的效果。在你的情况下,你需要禁用它们:
((SimpleItemAnimator) mRecyclerView.getItemAnimator()).setSupportsChangeAnimations(false);
(默认的回收视图动画程序应该已经是 SimpleItemAnimator 的实例)
对于 Kotlin,
(mRecyclerView?.itemAnimator as SimpleItemAnimator).supportsChangeAnimations = false
您可以禁用项目动画。
mRecyclerView.setItemAnimator(null);
如果你想保持RecyclerView的动画效果,又不想看到闪烁的条目,可以按照以下步骤进行:
1. 直接更改视图组件状态
2. 直接更改适配器中的数据
3. 不需要通过调用notifyItemChanged()
手动刷新UI
直接更改视图并不能立即生效,更好的方法是使用payload
。
在你的适配器中:
override fun onBindViewHolder(
holder: RecyclerView.ViewHolder,
position: Int,
payloads: MutableList<Any>
) {
// Using payload to refresh partly
if (payloads.isNullOrEmpty()) {
// refresh all
onBindViewHolder(holder, position)
return
}
// just change one component's status which would not "flash".
(holder as YourHolder).apply{
// make you view change
// etc. checkBox.isChecked = true
}
}
并且使用它:
yourAdapter.notifyItemChanged(position, "sample_pay_load")
在您的适配器中使用 stableId .
调用 adapter.setHasStableIds(true)
并覆盖适配器类中的 getItemId(int position)
方法。
此外,对于每个项目从 getItemId(int position)
返回一些唯一的 id。不要简单地返回位置。
canReuseUpdatedViewHolder()
告诉RecyclerView
重复使用Viewholders。请参阅类似问题的答案:
https://dev59.com/Buo6XIcBkEYKwwoYFQLr#60427676
In animateChange() method, comment below 3 lines,
final float prevAlpha = oldHolder.itemView.getAlpha();
.
.
oldHolder.itemView.setAlpha(prevAlpha);
.
.
newHolder.itemView.setAlpha(0);
Set recyclerview item animator to that of your cloned class.
//注意:我了解如何在不改变新持有者的alpha值的情况下使解决方案工作,但这不是我的解决方案。我在stackoverflow上阅读过这个解决方案,但由于某种原因无法再找到它。分享这个解决方案是为了帮助其他开发人员。
DefaultItemAnimator()
类并重写了animateChange()
,但是没有任何变化。 - Andrew@Override
public void onBindViewHolder(@NonNull RecyclerAdapter.ViewHolder viewHolder, int position) {
Movie movie = movies.get(position);
Picasso.with(context)
.load(movie.getImageLink())
.into(viewHolder.itemView.posterImageView);
}
有 3 个参数的 onBindViewHolder(...):
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position, @NonNull List<Object> payloads) {
if (payloads.isEmpty()) {
super.onBindViewHolder(holder, position, payloads);
} else {
holder.itemView.setAlpha(1);
}
}
以下是我在onCreateViewHolder(...)方法中的viewHolder的itemView的onClickListener中调用的代码:
private void onMovieClick(int position, Movie movie) {
Bundle data = new Bundle();
data.putParcelable("movie", movie);
// This data(bundle) will be passed as payload for ItemHolderInfo in our animator class
notifyItemChanged(position, data);
}
注意:您可以通过在onCreateViewHolder(...)中调用viewHolder的getAdapterPosition()方法来获取此位置。
我还重写了getItemId(int position)方法,如下所示:
@Override
public long getItemId(int position) {
Movie movie = movies.get(position);
return movie.getId();
}
如果以上答案都不起作用,我希望这个能帮到你:在活动中调用setHasStableIds(true);
来设置我的适配器对象。
希望这可以帮助你!
for (i in 0 until adapter.itemCount) {
CoroutineScope(Main).launch {
adapter.notifyItemChanged(i)
}
}
adapter.notifyItemChanged(position, "CHANGE_TEXT_VIEW_ITEM");
然后在RecyclerViewAdapter中覆盖带有有效负载的onBindViewHolder方法。
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position, @NonNull List<Object> payloads) {
if (payloads.isEmpty()) {
super.onBindViewHolder(holder, position, payloads);
} else {
for (Object payload : payloads) {
if (payload.equals("CHANGE_TEXT_VIEW_ITEM")) {
//you have holder and position to do relevant changes
}
}
}
}
这将更新回收站项目而不会出现任何闪烁。同样可以通过notifyItemRangeChanged实现。