RecyclerView粘性头部,支持线性和网格布局,支持item添加和删除(无需再次排序)

这篇博客介绍了如何在RecyclerView中实现粘性头部,支持线性和网格布局,并且在item添加和删除时无需重新排序。作者提供了项目的GitHub链接,读者可以查看源码,重点关注StickyHeaderScrollerListener滑动监听类中的实现。

RecyclerView粘性头部

     1.实现原理:在外部添加一个与RecyclerView对齐的headerView,动态添加需要展示的header

     2.支持线性和网格布局

     3.支持item添加和删除(无需再次排序)

 

博主文笔太菜,不想多说,直接上项目链接

github:  https://github.com/PPQingZhao/StickyHeaderDemo

需要的伙伴自行看源码,主要实现在 StickyHeaderScrollerListener 滑动监听类中

 

下面贴出关键代码:  

package com.pp.stickyheaderdemo.adapter;

import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.util.SparseArray;
import android.view.View;
import android.view.ViewGroup;

import com.pp.stickyheaderdemo.mutilitem.StickyHeader;

/**
 * @author qing
 * 滑动监听
 * 用于实现粘性头部
 */
public class StickyHeaderScrollerListener extends RecyclerView.OnScrollListener {
    private static final String TAG = "StickyHeaderScroller";
    private final StickHeaderContainer mHeaderContainer;
    private final SparseArray<RecyclerView.ViewHolder> mHolderMap;

    public StickyHeaderScrollerListener(StickHeaderContainer container) {
        if (null == container) {
            throw new RuntimeException("StickHeaderContainer must not be null.");
        }
        this.mHeaderContainer = container;
        mHolderMap = new SparseArray<>();
    }

    @Override
    public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
        if (null == mHeaderAdapter) {
            throw new RuntimeException("StickyHeaderAdapter must not be null.");
        }

        if (dy > 0) {
            int headerHeight = mHeaderContainer.getMeasuredHeight();
            // header top边下的view
            View viewTop = recyclerView.findChildViewUnder(mHeaderContainer.getMeasuredWidth() * 0.5f, 1);
            // 获取view 在列表中的位置
            int positionTop = recyclerView.getChildAdapterPosition(viewTop);
            StickyHeader topHeaderItem = mHeaderAdapter.getHeaderItem(positionTop);
            boolean isHeaderTop = null != topHeaderItem && topHeaderItem.isHeader();

            // header交换时机: viewTop是header 并且 viewTop.getTop() <= 0
            if (isHeaderTop && viewTop.getTop() <= 0) {
                if (positionTop != mHeaderContainer.getHeaderPosition()) {

                    // 更新old header记录
                    mHeaderContainer.setOldHeaderPosition(mHeaderContainer.getHeaderPosition());

                    // 更新当前header记录
                    mHeaderContainer.setHeaderPosition(positionTop);

                    // 更新map , key:当前header  value: 当前header的前一个header
                    mHeaderContainer.putPreviousValue(mHeaderContainer.getOldHeaderPosition());

                    RecyclerView.ViewHolder holder = getHolder(mHeaderContainer.getHeaderPosition());
                    if (null != holder && null == holder.itemView.getParent()) {
                        // 更新headerview
                        addHeaderView(holder);
                    }
                }
            }

            // header bottom边下的view
            View viewBottom = recyclerView.findChildViewUnder(mHeaderContainer.getMeasuredWidth() * 0.5f, headerHeight);
            // 获取view 在列表中的位置
            int positionBottom = recyclerView.getChildAdapterPosition(viewBottom);
            StickyHeader bottomHeaderItem = mHeaderAdapter.getHeaderItem(positionBottom);
            boolean isHeaderBottom = null != bottomHeaderItem && bottomHeaderItem.isHeader();
            int viewBottomTop = null == viewBottom ? 0 : viewBottom.getTop();
            if (isHeaderBottom && 0 <= viewBottomTop && viewBottomTop <= headerHeight) {
                mHeaderContainer.setHeaderTranslationY(viewBottomTop - headerHeight);
            } else {
                mHeaderContainer.setHeaderTranslationY(0);
            }

        } else if (dy <= 0) {
            int headerHeight = mHeaderContainer.getMeasuredHeight();
            View viewUnder = null;
            // dy 等于0时,取mHeaderContainer top边下的item,通常是 删除/添加 itme时触发
            if (0 == dy) {
                viewUnder = recyclerView.findChildViewUn
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值