Android多头部粘性RecyclerView实现求助:头部无法粘滞
解决多头部粘性RecyclerView的问题
首先,咱们先梳理下你当前实现里的两个核心问题:
一、修复头部识别逻辑的错误
你现在的isPositionHeader方法只把position == 0的item当成头部,但你的数据源里每个分组都有自己的头部(通过isHeader=true标记),这就导致后面的头部都被当成普通item处理了。
把Adapter里的头部判断逻辑改成根据ItemObject的属性来判断:
private boolean isPositionHeader(int position) { // 替换原来的position==0,用数据里的isHeader标记判断 return itemObjects.get(position).isHeader(); }
同时注意你getDataSource里的小错误:你把list1加了两次,改成只加一次就行:
private List <ItemObject> getDataSource(){ List<ItemObject> list1 = new ArrayList <ItemObject>(); list1.add(new ItemObject("First Header",true)); list1.add(new ItemObject("This is the item content in the first position")); list1.add(new ItemObject("This is the item content in the second position")); List <ItemObject> list2 = new ArrayList <ItemObject>(); list2.add(new ItemObject("Second Header",true)); list2.add(new ItemObject("This is the item content in the first position")); list2.add(new ItemObject("This is the item content in the second position")); List <ItemObject> list3 = new ArrayList <ItemObject>(); list3.add(new ItemObject("Third Header",true)); list3.add(new ItemObject("This is the item content in the first position")); list3.add(new ItemObject("This is the item content in the second position")); List <ItemObject> finalList = new ArrayList <ItemObject>(); finalList.addAll(list1); finalList.addAll(list2); finalList.addAll(list3); return finalList; }
二、实现粘性头部功能
原生的LinearLayoutManager本身不支持粘性头部,咱们可以通过自定义RecyclerView.ItemDecoration来实现——这个方案比自定义LayoutManager简单很多,适合新手。
1. 自定义StickyHeaderDecoration类
public class StickyHeaderDecoration extends RecyclerView.ItemDecoration { private RecyclerViewAdapter adapter; public StickyHeaderDecoration(RecyclerViewAdapter adapter) { this.adapter = adapter; } @Override public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) { super.onDrawOver(c, parent, state); // 获取当前可见的第一个item位置 int firstVisiblePos = ((LinearLayoutManager) parent.getLayoutManager()).findFirstVisibleItemPosition(); if (firstVisiblePos == RecyclerView.NO_POSITION) return; // 找到当前需要悬浮的头部位置:如果当前可见item不是头部,就找它前面最近的头部 int headerPos = firstVisiblePos; if (!adapter.isPositionHeader(firstVisiblePos)) { headerPos = findPrevHeaderPos(firstVisiblePos); if (headerPos == RecyclerView.NO_POSITION) return; } // 创建并绑定头部View RecyclerView.ViewHolder headerHolder = adapter.createViewHolder(parent, RecyclerViewAdapter.TYPE_HEADER); adapter.onBindViewHolder(headerHolder, headerPos); View headerView = headerHolder.itemView; // 测量并布局头部View int widthSpec = View.MeasureSpec.makeMeasureSpec(parent.getWidth(), View.MeasureSpec.EXACTLY); int heightSpec = View.MeasureSpec.makeMeasureSpec(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED); headerView.measure(widthSpec, heightSpec); headerView.layout(0, 0, headerView.getMeasuredWidth(), headerView.getMeasuredHeight()); // 计算头部绘制的Y坐标:处理下一个头部上来时的推挤效果 int drawTop = parent.getPaddingTop(); int nextHeaderPos = findNextHeaderPos(headerPos); if (nextHeaderPos != RecyclerView.NO_POSITION) { View nextHeaderView = parent.findViewHolderForAdapterPosition(nextHeaderPos).itemView; int offset = nextHeaderView.getTop() - headerView.getMeasuredHeight() - parent.getPaddingTop(); if (offset < 0) { drawTop += offset; } } // 绘制悬浮头部 c.save(); c.translate(parent.getPaddingLeft(), drawTop); headerView.draw(c); c.restore(); } // 找当前位置之前最近的头部 private int findPrevHeaderPos(int currentPos) { for (int i = currentPos - 1; i >= 0; i--) { if (adapter.isPositionHeader(i)) return i; } return RecyclerView.NO_POSITION; } // 找当前头部之后的下一个头部 private int findNextHeaderPos(int currentHeaderPos) { for (int i = currentHeaderPos + 1; i < adapter.getItemCount(); i++) { if (adapter.isPositionHeader(i)) return i; } return RecyclerView.NO_POSITION; } }
2. 在MainActivity中添加Decoration
修改你的RecyclerView初始化代码,加上这个粘性头部装饰:
recyclerView = findViewById(R.id.recyclerView); LinearLayoutManager linearLayoutManager = new LinearLayoutManager(MainActivity.this); recyclerView.setLayoutManager(linearLayoutManager); recyclerView.setHasFixedSize(true); RecyclerViewAdapter adapter = new RecyclerViewAdapter(this , getDataSource()); // 新增:添加粘性头部Decoration recyclerView.addItemDecoration(new StickyHeaderDecoration(adapter)); recyclerView.setAdapter(adapter);
最后说下你的初始实现思路
你的Adapter基础框架是对的(区分了头部和普通item),但核心问题有两个:一是头部识别逻辑错误,二是没意识到原生LayoutManager不支持粘性头部。现在修改后就能实现你要的多头部粘性效果了。
内容的提问来源于stack exchange,提问作者user11523459
相关产品推荐
相关产品推荐

