luizgrp / SectionedRecyclerViewAdapter

An Adapter that allows a RecyclerView to be split into Sections with headers and/or footers. Each Section can have its state controlled individually.
MIT License
1.68k stars 372 forks source link

getSectionForPosition(int) does not account for visible empty sections #80

Closed xannonite closed 6 years ago

xannonite commented 7 years ago
Include the following:
Reproduction Steps
  1. Call getSectionForPosition(int) on an adapter that contains visible empty sections.
Expected Result

Get the section containing the given position.

Actual Result

If the section for the given position is preceded by visible empty sections, then the section returned will be off by the number of preceding visible sections.

Solution

Replace line 356 of SectionedRecyclerViewAdapter.java as follows:

Before:

currentPos += sectionTotal;

After:

currentPos += sectionTotal > 0 ? sectionTotal : 1;
luizgrp commented 6 years ago

Hi @xannonite,

The current behaviour is intended, getSectionForPosition was created to find the section that an item displayed on the RecyclerView belongs to, based on the position provided by the RecyclerView.Adapter, like in onBindViewHolder.

It uses the method Section.getSectionItemsTotal to find the total of visible components of the section (header, footer, items..). If the section is visible but has no components visible in the recyclerview then it's not taken into account.

Do you have a scenario with a Section with no headers, no footers and no items, but still has something visible in the RecyclerView?

xannonite commented 6 years ago

@luizgrp In this particular case I have sections with header views and empty views. When a section has no items, I set the state to State.EMPTY, which displays the empty view. The header view is also displayed like so:

I am extending Section and overriding getContentItemsTotal, getEmptyViewHolder, getHeaderViewHolder, getItemViewHolder, and the matching onBindViewHolder methods. getContentItemsTotal returns the size of the backing list, which is zero when there are no items.

Everything works as expected except for the issue with getSectionForPosition(int). I copied the method and tweaked it as described to work around the issue.

luizgrp commented 6 years ago

I wrote an unit test with your scenario and it's working as intended:

    @Test
    public void getSectionForPosition_() {
        // Given
        HeadedSectionStub sectionStub1 = new HeadedSectionStub(0);
        sectionStub1.setState(State.EMPTY);
        sectionAdapter.addSection(sectionStub1);

        HeadedSectionStub sectionStub2 = new HeadedSectionStub(2);
        sectionAdapter.addSection(sectionStub2);

        HeadedSectionStub sectionStub3 = new HeadedSectionStub(0);
        sectionStub3.setState(State.EMPTY);
        sectionAdapter.addSection(sectionStub3);

        // When
        Section result0 = sectionAdapter.getSectionForPosition(0);
        Section result1 = sectionAdapter.getSectionForPosition(1);
        Section result2 = sectionAdapter.getSectionForPosition(2);
        Section result3 = sectionAdapter.getSectionForPosition(3);
        Section result4 = sectionAdapter.getSectionForPosition(4);
        Section result5 = sectionAdapter.getSectionForPosition(5);
        Section result6 = sectionAdapter.getSectionForPosition(6);

        // Then
        assertSame(result0, sectionStub1); // Section 1 Header
        assertSame(result1, sectionStub1); // Section 1 EMPTY content
        assertSame(result2, sectionStub2); // Section 2 Header
        assertSame(result3, sectionStub2); // Section 2 item 0
        assertSame(result4, sectionStub2); // Section 2 item 1
        assertSame(result5, sectionStub3); // Section 3 Header
        assertSame(result6, sectionStub3); // Section 3 EMPTY content
    }

I'm closing the issue as it doesn't seem to be related to the library but to your project. In this case please open an issue in Stackoverflow using the tag sectionedrecyclerviewadapter.