我使用 DelegateAdapters 在父 RecyclerView 中显示不同的部分。 在此代码中,我添加了两个部分(AuthorTracksDelegateItem 和 NewReleasesDelegateItem),它们具有标题和曲目列表,然后将显示在嵌套水平列表中。 另外,我将观察 LiveData,以便当另一个轨道出现时我可以添加第三部分(PlayerDelegateItem),然后一切都如常
fun setAdapter(recyclerView: RecyclerView){
//Add sections
val testData = listOf(
AuthorTracksDelegateItem(title = "Beatles", tracks = homeViewModel.getTracks("Beatles")),
NewReleasesDelegateItem(title = "New releases", albums = homeViewModel.getNewReleases()),
)
compositeAdapter.setItems(testData)
//Observe and add new section
homeViewModel.getTracks("Imagine dragons").observe(viewLifecycleOwner) { tracks ->
if(tracks.isNotEmpty()){
compositeAdapter.addToEnd(PlayerDelegateItem(title = "Last play", content = tracks.first()))
}
}
//other
recyclerView.layoutManager = LinearLayoutManager(context)
recyclerView.adapter = compositeAdapter
val padding = resources.getDimensionPixelSize(R.dimen.section_margin)
recyclerView.addItemDecoration(MarginItemDecoration(padding, padding*10, padding))
}
之后,在 ViewHolders 中,我还创建了新的嵌套列表,一切都像往常一样。
inner class NewReleasesViewHolder(itemView: View):
DelegateViewHolder(itemView)
{
private val title = itemView.findViewById<TextView>(R.id.section_title)
private val recyclerView = itemView.findViewById<RecyclerView>(R.id.rv_horizontal_tracks)
private val adapter = NewReleasesAdapter()
override fun bind(item: IDelegateAdapterItem) {
title.text = item.id() as String
(item.content() as LiveData<List<Album>>).observeForever { albums ->
adapter.setItems(albums)
}
setupRecycleView()
}
private fun setupRecycleView(){
val layout = LinearLayoutManager(itemView.context)
layout.orientation = LinearLayoutManager.HORIZONTAL
recyclerView.adapter = adapter
recyclerView.layoutManager = layout
recyclerView.addItemDecoration(
MarginItemDecoration(
startSpace = itemView.resources.getDimensionPixelSize(R.dimen.content_horizontal_margin),
endSpace = itemView.resources.getDimensionPixelSize(R.dimen.content_horizontal_margin),
betweenSpace = itemView.resources.getDimensionPixelSize(R.dimen.items_margin),
isHorizontal = true
)
)
}
}
override fun createViewHolder(binding: View): RecyclerView.ViewHolder {
return NewReleasesViewHolder(binding)
}
override fun getLayoutId(): Int {
return R.layout.section_nested_list
}
inner class TrackViewHolder(itemView: View): DelegateViewHolder(itemView){
val title = itemView.findViewById<TextView>(R.id.section_title)
val recyclerView = itemView.findViewById<RecyclerView>(R.id.rv_horizontal_tracks)
val adapter = LargeTracksAdapter()
override fun bind(item: IDelegateAdapterItem) {
title.text = item.id() as String
(item.content() as LiveData<List<Track>>).observeForever { tracks ->
adapter.setItems(tracks)
}
setupRecycleView()
}
fun setupRecycleView(){
val layout = LinearLayoutManager(itemView.context)
layout.orientation = LinearLayoutManager.HORIZONTAL
recyclerView.layoutManager = layout
recyclerView.adapter = adapter
recyclerView.addItemDecoration(MarginItemDecoration(
startSpace = itemView.resources.getDimensionPixelSize(R.dimen.content_horizontal_margin),
endSpace = itemView.resources.getDimensionPixelSize(R.dimen.content_horizontal_margin),
betweenSpace = itemView.resources.getDimensionPixelSize(R.dimen.items_margin),
isHorizontal = true
))
recyclerView.invalidateItemDecorations()
}
}
为了在元素之间添加填充,我使用 ItemDecoration
class MarginItemDecoration(
private val startSpace: Int = 0,
private val endSpace: Int = 0,
private var betweenSpace: Int = 0,
private val isHorizontal: Boolean = false): RecyclerView.ItemDecoration() {
init {
betweenSpace /= 2
}
override fun getItemOffsets(
outRect: Rect,
view: View,
parent: RecyclerView,
state: RecyclerView.State
) {
val size = parent.adapter?.itemCount ?: 0
val itemPosition = parent.getChildAdapterPosition(view)
if (isHorizontal) {
outRect.left = getStartSpace(itemPosition)
outRect.right = getEndSpace(itemPosition, size)
} else {
outRect.top = getStartSpace(itemPosition)
outRect.bottom = getEndSpace(itemPosition, size)
}
}
private fun getStartSpace(
itemPosition: Int
): Int = when (itemPosition) {
0 -> startSpace
else -> betweenSpace
}
private fun getEndSpace(
itemPosition: Int,
size: Int,
): Int = when (itemPosition) {
size-1 -> endSpace
else -> betweenSpace
}
}
虽然我使用了dimension.xml中相同的固定值,但缩进显示不同,由于某种原因,在第二部分中它是两倍大
我注意到,当将新部分添加到父 RecyclerView 时,缩进会中断,我尝试将延迟设置为 5 秒。一切都很好,但添加缩进后,它们又坏了。 我尝试添加 invalidateItemDecorations() 但这也没有帮助。也许我在错误的地方或者没有正确使用它们,因为一个新的部分被添加到父 RecyclerView 中,并且嵌套的缩进被破坏了。 我尝试使用不同的布局和不同的 ID,但没有任何帮助。 我还尝试添加几个部分,只是复制它们,但发生了完全奇怪的事情
//Add sections
val testData = listOf(
AuthorTracksDelegateItem(title = "Beatles", tracks = homeViewModel.getTracks("Beatles")),
NewReleasesDelegateItem(title = "New releases", albums = homeViewModel.getNewReleases()),
AuthorTracksDelegateItem(title = "Linkin Park", tracks = homeViewModel.getTracks("Linkin Park")),
AuthorTracksDelegateItem(title = "21 pilots", tracks = homeViewModel.getTracks("21 pilots")),
)
我预计在后续的每个部分中,元素之间的空间都会加倍,但事实却是这样: 通过观察添加的部分(即使它是零)正常显示,但那里没有嵌套列表
我实在不明白他到底为什么要这样,为什么同一个类的第1、2、4节显示完全不同 源代码:https://github.com/Ikrom27/music-club-classic
也许,当添加新元素时,所有嵌套列表都会再次重绘,并向其中添加第二个 itemDecoration。因此,每次您需要删除所有装饰或添加之前,请检查列表中是否没有其他装饰
if (recyclerView.itemDecorationCount == 0) {
recyclerView.addItemDecoration(MarginItemDecoration(
startSpace = itemView.resources.getDimensionPixelSize(R.dimen.content_horizontal_margin),
endSpace = itemView.resources.getDimensionPixelSize(R.dimen.content_horizontal_margin),
betweenSpace = itemView.resources.getDimensionPixelSize(R.dimen.items_margin),
isHorizontal = true
))
}