timehop / sticky-headers-recyclerview

[UNMAINTAINED] Sticky Headers decorator for Android's RecyclerView
Apache License 2.0
3.74k stars 755 forks source link

Problem of header click event when the data set changed #162

Open Shouheng88 opened 6 years ago

Shouheng88 commented 6 years ago

Hello, project owner, I recently used your library in my project. It runs perfectly when there is no click event.

But when I added the click event to header view, after the data set changed, the item may perform unexpected action -- the same as clicking the header.

I guess this may occurred due to the cached views, so is there any method to solve this problem ? If this is one known issue, I'd be glad to make contribution to this project.

Shouheng88 commented 6 years ago

My code was just as below, when I changed the data set and then click one normal item, it will show the month pick dialog as header view is clicked.

Part 1. config the adapter. Error occur when normal item is clicked, just perform the same as the header view.

        StickyRecyclerHeadersDecoration headersDecor = new StickyRecyclerHeadersDecoration(monthAdapter);
        getBinding().rv.addItemDecoration(headersDecor);
        getBinding().rv.setAdapter(monthAdapter);
        getBinding().rv.setFakeHeader(getBinding().lSection.getRoot());
        StickyRecyclerHeadersTouchListener touchListener = new StickyRecyclerHeadersTouchListener(getBinding().rv, headersDecor);
        touchListener.setOnHeaderClickListener((header1, position, headerId) -> {
            SensorEvent.getInstance(TrackEvent.consumption_time).send();
            // The error usually occur here, the normal item will show the dialog
            showYearMonthPicker(headerId);
        });
        getBinding().rv.addOnItemTouchListener(touchListener);
        monthAdapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() {
            @Override
            public void onChanged() {
                headersDecor.invalidateHeaders();
            }
        });

Part 2. implement the StickyRecyclerHeadersAdapter:

    @Override
    public long getHeaderId(int position) {
        if (position < getHeaderLayoutCount()) {
            return -1;
        } else {
            SimpleInvoice simpleInvoice = getData().get(position - getHeaderLayoutCount()).simpleInvoice;
            return TimeUtils.getMonthKey(sortField == SortField.Date ? simpleInvoice.getDate() : simpleInvoice.getCreatedAt());
        }
    }

    @Override
    public BaseViewHolder onCreateHeaderViewHolder(ViewGroup parent) {
        View view = LayoutInflater.from(context).inflate(R.layout.item_section_title, parent, false);
        return new BaseViewHolder(view);
    }

    @Override
    public void onBindHeaderViewHolder(BaseViewHolder holder, int position) {
        SimpleInvoice simpleInvoice = getData().get(position - getHeaderLayoutCount()).simpleInvoice;
        Date date = sortField == SortField.Date ? simpleInvoice.getDate() : simpleInvoice.getCreatedAt();
        String strDate = TimeUtils.formatDate(date, DateFormat.YYYY_MMM);
        holder.setText(R.id.tv_date, strDate);
        long monthKey = TimeUtils.getMonthKey(date);
        TotalAmount totalAmount = totalAmountLongSparseArray.get(monthKey);
        if (totalAmount != null) {
            double amount = totalAmount.getAmount();
            holder.setText(R.id.tv_expand, PalmUtils.formatString(R.string.section_title_expand, amount));
        }
    }

Part 3. To change the data set. Below I used a wrapped method to add new data set. The method inside will call the Adapter.notifyDataSetChanged() automatically:

    monthAdapter.setNewData(SelectableInvoice.wrap(indexList.getInvoiceList()));

I would be very glad if anyone could give me any advice :)

Shouheng88 commented 6 years ago

I found that the library that I used was :

api 'com.timehop.stickyheadersrecyclerview:library:0.4.3@aar'

which is the latest version. As the READEME history showed that the bug

0.4.3 (12/24/2015) - Change minSDK to 11, fix issue with header bounds caching

was fixed in 0.4.3, but the code was not found in the release version. I noticed the commit was made at 2015-12-11 at StickyRecyclerHeadersDecoration.invalidateHeaders():

  public void invalidateHeaders() {
    mHeaderProvider.invalidate();
    mHeaderRects.clear(); // This line was added to clear the header Rect cache
  }

The line above was added to clear the header rect cache, but was not included in the 0.4.3 release version.