嵌套 RecycleView 中的 ItemDecoration 在父 RecycleView 中添加新项目后会更改填充

问题描述 投票:0回答:1

我在做什么

我使用 DelegateAdapters 在父 RecyclerView 中显示不同的部分。 在此代码中,我添加了两个部分(AuthorTracksDelegateItemNewReleasesDelegateItem),它们具有标题和曲目列表,然后将显示在嵌套水平列表中。 另外,我将观察 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中相同的固定值,但缩进显示不同,由于某种原因,在第二部分中它是两倍大 screenshot

我尝试了什么

我注意到,当将新部分添加到父 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. 第一部分(Beatles)也正常显示
  2. 第二部分(新版本)已经在嵌套列表中双缩进
  3. 第三个部分(Linkin Park)在嵌套列表中也有正常的填充,但该部分本身在底部增加了填充(我对最后一个元素这样做了,这样它就不会与导航栏重叠,但它不是最后一个元素)
  4. 第四部分(21 名飞行员)与前一个部分属于同一类别,但嵌套列表中的缩进又不正确

我实在不明白他到底为什么要这样,为什么同一个类的第1、2、4节显示完全不同 源代码:https://github.com/Ikrom27/music-club-classic

android kotlin android-recyclerview adapter
1个回答
0
投票

可能的解决方案

也许,当添加新元素时,所有嵌套列表都会再次重绘,并向其中添加第二个 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
            ))
        }
© www.soinside.com 2019 - 2024. All rights reserved.