365bet体育|www.635288com-365体育手机在线

热门关键词: 365bet体育,www.635288com,365体育手机在线

效果这是一个

2020-03-17 作者:365bet体育   |   浏览(131)

先看个效果

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

实现思路:

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

既然是利用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, RecyclerView parent, State state) { onDrawOver(c, parent); } public void getItemOffsets(Rect outRect, View view, RecyclerView parent, State state) { getItemOffsets(outRect, ((LayoutParams) view.getLayoutParams.getViewLayoutPosition(), parent); }}

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

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

RecyclerView 的背景、onDraw绘制的内容、ItemonDrawOver绘制的内容,各层级关系如下:

图片 2层级关系

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

  • 定义分割线高度
private int mHeight = 5; //分割线高度
  • 通过getItemOffsets预留空间
@Overridepublic void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { super.getItemOffsets(outRect, view, parent, state); int position = parent.getChildAdapterPosition; if (position != 0) { //第一个item预留空间 outRect.top = mHeight; }}
  • 然后在onDraw中绘制
@Overridepublic void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) { super.onDraw(c, parent, 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; final int bottom = childView.getTop(); final int top = bottom - mHeight; c.drawRect(left, top, right, bottom, mPaint); }}

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

图片 3效果(详情代码见底部链接)

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

图片 4效果1

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

  • 定义一个interface,根据position通过接口方法getGroupName获取当前省名(由Activity实现)
public interface GroupListener { String getGroupName(int position);}
  • 创建StickyDecoration继承RecyclerView.ItemDecoration
  • 定义isFirstInGroup方法。根据前一个省份,判断当前是否为新的省份
//判断是不是组中的第一个位置//根据前一个组名,判断当前是否为新的组private boolean isFirstInGroup { if  { return true; } else { String prevGroupId = getGroupName; String groupId = getGroupName; return !TextUtils.equals(prevGroupId, groupId); }}

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

  • 重写getItemOffsets方法,为悬浮栏预留空间
@Overridepublic void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { super.getItemOffsets(outRect, view, parent, state); int pos = parent.getChildAdapterPosition; String groupId = getGroupName; if (groupId == null) return; //只有是同一组的第一个才显示悬浮栏 if (pos == 0 || isFirstInGroup { outRect.top = mGroupHeight; }}

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

  • 重写onDrawOver方法
@Overridepublic void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) { super.onDrawOver(c, parent, 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对应的Group String currentGroupName = null; //当前item对应的Group for (int i = 0; i < childCount; i  ) { View view = parent.getChildAt; int position = parent.getChildAdapterPosition; preGroupName = currentGroupName; currentGroupName = getGroupName; 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, right, top, mGroutPaint); Paint.FontMetrics fm = mTextPaint.getFontMetrics(); //文字竖直居中显示 float baseLine = top - (mGroupHeight - (fm.bottom - fm.top)) / 2 - fm.bottom; c.drawText(currentGroupName, left   mLeftMargin, baseLine, mTextPaint); }}

通过变量preGroupIdcurrentGroupId来保存当前分组名和上一个分组名。当前Item与上一个Item为同一个分组时,跳过该Item的绘制。其中代码:

float top = Math.max(mGroupHeight, view.getTop;

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

if (!currentGroupName.equals(nextGroupName) && viewBottom < top) { top = viewBottom; }

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

到目前为止,一个带有悬浮功能的列表就实现了。(详细代码见底部链接)

图片 5--

当我们利用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 parent, RecyclerView.State state) { ... for (int i = 0; i < childCount; i  ) { ... //根据position获取View View groupView = mGroupListener.getGroupView; if (groupView == null) return; ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, mGroupHeight);groupView.setLayoutParams(layoutParams); groupView.setDrawingCacheEnabled; groupView.measure( View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED), View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)); //指定高度、宽度的groupView groupView.layout(0, 0, right, mGroupHeight); groupView.buildDrawingCache(); Bitmap bitmap = groupView.getDrawingCache(); c.drawBitmap(bitmap, left, top - mGroupHeight, null); }}

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

效果:

图片 6效果2

(详细代码见底部链接)

已封装成库,欢迎来提Issues

repositories { jcenter()// If not already there}dependencies { compile 'com.gavin.com.library:stickyDecoration:x.x.x'}

链接

  • LinearLayoutManager
  • GridLayoutManager
  • 点击事件
  • 分割线

详细用法级源码请看Github

Android-使用RecyclerView的ItemDecoration 实现炫酷的 吸顶效果RecycleView的学习(一篇不错的博客,没有投稿,所以看得人不多)Android RecyclerView 使用完全解析 体验艺术般的控件

本文由365bet体育发布于365bet体育,转载请注明出处:效果这是一个

关键词: 365bet体育备用 Android 效果 RecyclerView