关于RecycleView的子元素锁定吸顶效果
最近有一关于列表元素锁定吸顶的需求。处理方案比较简单的,在外层布局添加一个相同的标题栏控件,根据控件在滚动过中的位置来判断显示隐藏,从而达到效果。使用的关键代码是:
int[] loc = new int[2]; view.getLocationOnScreen(loc); int[] fitLoc = new int[2]; outView.getLocationOnScreen(fitLoc); if (loc[1] <= fitLoc[1]){ //外部标题栏显示 }else{ //外部标题栏隐藏 }
在这个过程中,碰到几个问题:
1、当数据比较多,超过一个屏时,屏下所要固定的标题栏,显示状态时InVisible的状态,且所在屏幕位置坐标为(0, 0),这会导致显示判断的错误,这一情况做过滤处理;
2、当数据量从多到少或从少到多变化时,外层标题栏都要默认隐藏,列表标题栏都要默认显示(在onBindViewHolder()写);
以上如果是针对子项某一元素吸顶就够了,如果是对多个子元素需要吸顶需加如下处理:
1、列表的数据结构使用Map<TitleBean, List<ContentBean>>,的键值对, 重写的adapter的getItemCount()t,用TitleBean+ItemBean作为总数。这时我们可以建立算法(计算Map与List一一对应的对象),如果界面展示的是九宫格布局GridLayoutManager的方式,可以重写onAttachedToRecyclerView进行一维列表化。(关于公有/私有修饰,大家随意 )
private Map<TitleBean, List<ContentBean<T>>> data = new TreeMap<>(); @Override public void onAttachedToRecyclerView(@NonNull RecyclerView recyclerView) { super.onAttachedToRecyclerView(recyclerView); RecyclerView.LayoutManager manager = recyclerView.getLayoutManager(); if (manager instanceof GridLayoutManager) { final GridLayoutManager gridManager = ((GridLayoutManager) manager); gridManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() { @Override public int getSpanSize(int position) { return getItemViewType(position) != Type.Content ? gridManager.getSpanCount() : 1; } }); } } private BaseTimeBean<T> getItemBean(int pos){ if(data.isEmpty()) return null; int count = 0; for(TimeBean titleBean : data.keySet()){ count++; if (count -1 == pos) return titleBean; else { List<ImageBean<T>> contentBeans = data.get(titleBean); if (count + contentBeans.size() -1 <= pos){ int index = pos-count; return (index >= 0 && index < contentBeans.size()) ? contentBeans.get(pos- count) : null; }else { count += contentBeans.size(); } } } return null; } public class ItemBean<T>{ public String id; public String name; public T t; } public class TimeBean extends ItemBaen{} public class ContentBean<T> extends ItemBean<T>{}
2、添加列表控件的滑动监听了,如addOnScrollListener,重写onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy)方法,用布局管理器找第一个可是元素位置findFirstVisibleItemPosition,传入getTitleBean方法中,找打对应的数据, 进而赋值到吸顶控件上。
private TitleBean getTitleBean(int pos){ if(data.isEmpty()) return null; int count = 0; for(TitleBean titleBean : data.keySet()){ count++; if (count -1 == pos) return titleBean; else { int size = data.get(titleBean).size(); if (count + size -1 <= pos){ int index = pos-count; return titleBean; }else { count += size; } } } return null; }