Android RecyclerView打造悬浮效果的实现代码

Android RecyclerView打造悬浮效果的实现代码,第1张

概述本文介绍了AndroidRecyclerView悬浮效果,分享给大家,具体如下:先看个效果这是一个City列表,每个City都有所属的Province,需要在滑动的时候,将对应的Province悬浮在顶部。悬浮顶部的Province需要根据列表的滑

本文介绍了AndroID RecyclerVIEw悬浮效果,分享给大家,具体如下:

先看个效果

这是一个City列表,每个City都有所属的Province,需要在滑动的时候,将对应的Province悬浮在顶部。悬浮顶部的Province需要根据列表的滑动而适当改变位置,实现“顶上去”的效果。

实现思路:

利用RecyclerVIEw.Itemdecoration绘制Province(就像绘制分割线一样) 同一组的City,只绘制一个Province 计算偏移,将当前Province固定在顶部 根据列表滑动,实现偏移效果

Itemdecoration

既然是利用RecyclerVIEw.Itemdecoration实现的悬浮效果,那么有必要了解下它。

Itemdecoration字面意思:Item的装饰。是的!是装饰!不只是画分割线。

其实Itemdecoration的功能非常强大,而我们平时只是用它来实现分割线的效果(至少我是这样)。因此,可能很多同学认为Itemdecoration就是用来绘制分割线的。其实不然,Itemdecoration的功能远不止是分割线的绘制。

先看下RecyclerVIEw.Itemdecoration的源码(部分):

public static abstract class Itemdecoration { ... public voID onDraw(Canvas c,RecyclerVIEw parent,State state) {  onDraw(c,parent); } public voID onDrawOver(Canvas c,State state) {  onDrawOver(c,parent); } public voID getItemOffsets(Rect outRect,VIEw vIEw,State state) {  getItemOffsets(outRect,((LayoutParams) vIEw.getLayoutParams()).getVIEwLayoutposition(),parent); }}

里面是我们常用的三个方法:

getItemOffsets:通过Rect为每个Item设置偏移,用于绘制decoration。 onDraw:通过该方法,在Canvas上绘制内容,在绘制Item之前调用。(如果没有通过getItemOffsets设置偏移的话,Item的内容会将其覆盖) onDrawOver:通过该方法,在Canvas上绘制内容,在Item之后调用。(画的内容会覆盖在item的上层)

RecyclerVIEw 的背景、onDraw绘制的内容、Item、onDrawOver绘制的内容,各层级关系如下:

层级关系

绘制分割线

先看看一般的分割线绘制。

定义分割线高度

private int mHeight = 5; //分割线高度

通过getItemOffsets预留空间

@OverrIDepublic voID getItemOffsets(Rect outRect,RecyclerVIEw.State state) { super.getItemOffsets(outRect,vIEw,parent,state); int position = parent.getChildAdapterposition(vIEw); if (position != 0) {  //第一个item预留空间  outRect.top = mHeight; }}

然后在onDraw中绘制

@OverrIDepublic voID onDraw(Canvas c,RecyclerVIEw.State state) { super.onDraw(c,state); final int left = parent.getleft(); final int right = parent.getRight(); final int childCount = parent.getChildCount(); for (int i = 0; i < childCount; i++) {  final VIEw childVIEw = parent.getChildAt(i);  final int bottom = childVIEw.gettop();  final int top = bottom - mHeight;  c.drawRect(left,top,right,bottom,mPaint); }}

获取当前RecyclerVIEw的Item数量,遍历每个Item。在对应的位置绘制一个高度为mHeight的矩形 ,从而实现分割线的效果。

(详情代码见底部链接)

打造悬浮效果

这是一个城市列表,根据省份分组,相同的城市只会显示一个省份。滚动城市列表时,省份会悬浮在顶部。效果如下:

实现

由于需要悬浮效果,所以需要在onDrawOver中绘制分组。

定义一个interface,根据position通过接口方法getGroupname获取当前省名(由Activity实现)

public interface GroupListener { String getGroupname(int position);}

创建Stickydecoration继承RecyclerVIEw.Itemdecoration

定义isFirstInGroup方法。根据前一个省份,判断当前是否为新的省份

//判断是不是组中的第一个位置//根据前一个组名,判断当前是否为新的组private boolean isFirstInGroup(int pos) { if (pos == 0) { return true; } else { String prevGroupID = getGroupname(pos - 1); String groupID = getGroupname(pos); return !TextUtils.equals(prevGroupID,groupID); }}

通过position,对比上一个省份名称,判断当前省是否为第一个

重写getItemOffsets方法,为悬浮栏预留空间

@OverrIDepublic voID getItemOffsets(Rect outRect,state); int pos = parent.getChildAdapterposition(vIEw); String groupID = getGroupname(pos); if (groupID == null) return; //只有是同一组的第一个才显示悬浮栏 if (pos == 0 || isFirstInGroup(pos)) { outRect.top = mGroupHeight; }}

只有第一个Item或者新的省份才为悬浮栏预留空间

重写onDrawOver方法(重点)

@OverrIDepublic voID onDrawOver(Canvas c,RecyclerVIEw.State state) {super.onDrawOver(c,state);final int itemCount = state.getItemCount();final int childCount = parent.getChildCount();final int left = parent.getleft() + parent.getpaddingleft();final int right = parent.getRight() - parent.getpaddingRight();String preGroupname;  //标记上一个item对应的GroupString currentGroupname = null;  //当前item对应的Groupfor (int i = 0; i < childCount; i++) { VIEw vIEw = parent.getChildAt(i); int position = parent.getChildAdapterposition(vIEw); preGroupname = currentGroupname; currentGroupname = getGroupname(position); if (currentGroupname == null || TextUtils.equals(currentGroupname,preGroupname))  continue; int vIEwBottom = vIEw.getBottom(); float top = Math.max(mGroupHeight,vIEw.gettop());//top 决定当前顶部第一个悬浮Group的位置 if (position + 1 < itemCount) {  //获取下个Groupname  String nextGroupname = getGroupname(position + 1);  //下一组的第一个VIEw接近头部  if (!currentGroupname.equals(nextGroupname) && vIEwBottom < top) {   top = vIEwBottom;  } } //根据top绘制group c.drawRect(left,top - mGroupHeight,mGroutPaint); Paint.FontMetrics fm = mTextPaint.getFontMetrics(); //文字竖直居中显示 float baseline = top - (mGroupHeight - (fm.bottom - fm.top)) / 2 - fm.bottom; c.drawText(currentGroupname,left + mleftmargin,baseline,mTextPaint); }}

通过变量preGroupID和currentGroupID来保存当前分组名和上一个分组名。当前Item与上一个Item为同一个分组时,跳过该Item的绘制。

其中代码:

float top = Math.max(mGroupHeight,vIEw.gettop());

根据当前Item的位置确定绘制分组的位置。top将在mGroupHeight和vIEw.gettop()中取最大值,也就是说top将不会小于mGroupHeight,这样就能实现吸顶效果。

其中代码:

if (!currentGroupname.equals(nextGroupname) && vIEwBottom < top) {  top = vIEwBottom; }

当下个分组的顶部(当前Item的底部vIEwBottom可近似认为下个Item的顶部)距离RecyclerVIEw顶部小于top时,偏移当前分组位置。实现下一组上滑时候,当前分组上移;上一组下滑的时候,当前分组下移。
最后计算baseline,并绘制背景和文字。

到目前为止,一个带有悬浮功能的列表就实现了。

(详细代码见底部链接)

进阶

当我们利用Itemdecoration实现文字的悬浮的时候,是不是还可以搞点事情~ ~我有个大胆的想法
只有文字的悬浮怎么行!我还希望可以再来个icon?再来几个TextVIEw?来个自定义布局?那就来个自定义布局吧。

实现

实现的原理跟上面一样,由于需要自定义布局,所以需要在接口中添加一个获取VIEw的方法。

定义PowerGroupListener

public interface PowerGroupListener { String getGroupname(int position); VIEw getGroupVIEw(int position);}

相比之前,多了个getGroupVIEw方法,用来获取VIEw。

在onDrawOver中绘制

@OverrIDepublic voID onDrawOver(Canvas c,RecyclerVIEw.State state) { ... for (int i = 0; i < childCount; i++) {  ...  //根据position获取VIEw  VIEw groupVIEw = mGroupListener.getGroupVIEw(position);  if (groupVIEw == null) return;  VIEwGroup.LayoutParams layoutParams = new VIEwGroup.LayoutParams(VIEwGroup.LayoutParams.WRAP_CONTENT,mGroupHeight);groupVIEw.setLayoutParams(layoutParams);  groupVIEw.setDrawingCacheEnabled(true);  groupVIEw.measure(    VIEw.MeasureSpec.makeMeasureSpec(0,VIEw.MeasureSpec.UnspecIFIED),VIEw.MeasureSpec.makeMeasureSpec(0,VIEw.MeasureSpec.UnspecIFIED));  //指定高度、宽度的groupVIEw  groupVIEw.layout(0,mGroupHeight);  groupVIEw.buildDrawingCache();  Bitmap bitmap = groupVIEw.getDrawingCache();  c.drawBitmap(bitmap,left,null); }}

在原来的基础上做了点修改,通过接口的getGroupVIEw方法获取需要绘制的分组VIEw,将得到的VIEw绘制到指定位置。

效果:

(详细代码见底部链接)

源码链接

已封装成库,欢迎来提Issues

repositorIEs { jcenter()// If not already there}dependencIEs { compile 'com.gavin.com.library:stickydecoration:1.0.2'}

详细用法级源码请看Github

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持编程小技巧。

总结

以上是内存溢出为你收集整理的Android RecyclerView打造悬浮效果的实现代码全部内容,希望文章能够帮你解决Android RecyclerView打造悬浮效果的实现代码所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/web/1144056.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2022-05-31
下一篇2022-05-31

发表评论

登录后才能评论

评论列表(0条)

    保存