如何在 Adapter 类的 RecyclerView 中提供子项的条件可见性?
Posted
技术标签:
【中文标题】如何在 Adapter 类的 RecyclerView 中提供子项的条件可见性?【英文标题】:How to provide conditional visibility of a child-item in a RecyclerView in the Adapter class? 【发布时间】:2021-07-05 09:31:51 【问题描述】:我正在开发一个项目,该项目为每个屏幕实现 2 个视图、一个普通用户视图和一个管理员视图。与普通用户相比,管理员视图具有更多权限,例如从数据库中删除某些帖子或用户本身。
因此,如果 admin 权限为真(我在初始化适配器时将其作为参数值传递),我将这些功能按钮的可见性设置为 GONE
)。但我正在努力解决的问题是,我在哪里设置可见性,在onCreateViewHolder
方法或onBindViewHolder
方法中?我现在已经在 onCreateViewHolder 方法中设置了它,因为我已经阅读了一些 *** 答案,只是我们应该避免在 onBindViewHolder 方法中进行繁重的操作。但我想知道一个明确的答案。
以下是代码示例供参考:
适配器类声明:
class NoticesAdapter(options: FirestoreRecyclerOptions<NoticeModel>,
private val isAdmin: Boolean,
private val listener: INoticeListAdapter):
FirestoreRecyclerAdapter<NoticeModel, NoticesAdapter.NoticeViewHolder>(options)
onCreateViewHolder 方法:
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): NoticeViewHolder
val noticeListView = LayoutInflater.from(parent.context).inflate(R.layout.item_notice, parent, false)
val noticeListViewHolder = NoticeViewHolder(noticeListView)
if (!isAdmin)
noticeListViewHolder.deleteNoticeBtn.visibility = GONE
// On clicking the delete button on a notice by the admin
noticeListViewHolder.deleteNoticeBtn.setOnClickListener
val noticeSnapshot = snapshots.getSnapshot(noticeListViewHolder.adapterPosition)
listener.deleteNoticeBtnListener(noticeSnapshot)
return noticeListViewHolder
onBindViewHolder 方法:
override fun onBindViewHolder(holder: NoticeViewHolder, position: Int, model: NoticeModel)
holder.noticeText.text = model.noticeText
holder.noticeAuthor.text = MyUtils.getUserName()
holder.noticePostDate.text = model.datePosted
holder.noticePostTime.text = model.timePosted
【问题讨论】:
对于同一个持有者实例,将调用多少次onCreateViewHolder
和onBindViewHolder
? ...越低越好...所以“确定的答案”是: ....
@Selvin onCreateViewHolder,对吧? onCreateViewHolder 在第一次创建回收器视图时调用一次,而 onBindViewHolder 在每次数据更改时调用。只是想确认一下。再次感谢
是的,你也可以使用不同的布局(没有这个按钮)并且不要在点击监听器上设置
【参考方案1】:
RecyclerView.Adapter
的作用是:回收物品(顾名思义)。该列表不会同时对数据源上的每个项目有一个视图。适配器确保在内存中有足够的视图,以便始终平滑地呈现列表。当一行通过滚动离开视野时,该视图将被回收以在下一个进入屏幕大小的视图中重新使用。
这意味着onCreateViewHolder
仅在需要创建视图时调用。通常在适配器启动时,当用户快速或不规律地滚动以及数据集发生变化和需要时。
每次需要更新行上的数据以更新视图时,都会调用另一个方法onBindViewHolder
。每次有一行进入屏幕的视图字段时都会调用它。
所以教科书的答案是:在onBindViewHodlder
上执行,因为如果属性isAdmin
发生更改,则需要更新该行。通过在onCreateViewHolder
上执行此操作,只会在创建行时发生一次。
但是,您的 isAdmin
是构造函数上的一个 val,无法重新分配,因此这意味着当创建行时,按钮将永远隐藏或可见。这无关紧要,因为您的结构是要确定 admin 是否来自另一个与行数据结构派生的来源分开的来源。
如果在某些情况下你想:
使其在未来更加灵活和易于维护 或者您可能知道会有一个包含管理员而不是管理员行的列表然后解决方案是将isAdming
属性移动到您的NoticeModel
,这将意味着更改您的数据结构。
如果您想验证上述任何内容,请获取一个包含大量项目的数据源,然后添加 2 个日志,一个在 onCreateViewHolder
上,一个在 onBindViewHolder
上。你会看到 on create 只是有时被调用,而 on bind 总是被调用。
【讨论】:
另外为了解决问题中提到的问题,更改视图的可见性绝对不是“繁重”的操作。 因为如果属性 isAdmin 发生变化,那么该行将需要更新问题 如果管理员权限为真(我将其作为参数值传递时初始化适配器) 所以不,它不会改变每个项目 @SelvinBut, your isAdmin is a val on the constructor that can not be reassigned
是的,也包括在If in some case you want to...
感谢您的回答!好吧,您猜对了,admin 参数不会针对给定用户动态更改。所以我会避免在 onBindViewHolder 中设置可见性,因为它会使整个操作变得昂贵。我已经拥有来自 HubModel 类的 isAdmin 属性,所以我已经在那里处理了。再次感谢您的详细见解!
@HenryTwist 作为一般规则,任何适配器都不应该有繁重的操作,但是是的以上是关于如何在 Adapter 类的 RecyclerView 中提供子项的条件可见性?的主要内容,如果未能解决你的问题,请参考以下文章
View Binding 是不是支持 Adapter 类的视图绑定