[原创]recyclerview实现多行分组 给分组块加圆角.

2024-05-04 10:48

本文主要是介绍[原创]recyclerview实现多行分组 给分组块加圆角.,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

如果用多个recyclerview 或者里面多套个adapter当我没说,这里的实现方式是通过.借助griviewmanager和item

效果图是要达到这样的.当然这也是我最后搞完的图.

29a5f9a7d0ecebe84ed456ae9ff84eb.jpg
需求:

标题作为1行 内容为3列任意行.
标题内容分组 给标题内容包裹区域加圆角.
只有内容无标题的分组 就给内容区域加圆角

遇到的问题

1.当内容未满3列,颜色为recyclerview颜色或背景色.
2.边距写的不对,导致内容被扭曲,某个item出现背景色而且未和其他行对其.
3.滑动的时候发现我绘制的颜色掉了(是我粗心用的i而不是适配器位置导致)
4.判断末尾行
如果是末尾行直接填充白色圆角
5.如果没有标题,直接给内容加上左 和上右圆角.
6.最底部的边距没得.

其它

直接什么都不做的时候,没有圆角,没有分割线.
设置内容item为3列,但是不满3列,会导致出现背景颜色,有些朋友可能直接设置recyclerview背景了,但是你怕是不要处理圆角了??

如何实现?

  1. 使用GridLayoutManager
    2.给GridLayoutManager 设置setSpanSizeLookup 如果是标题就合并 getSpanSize 表示合并的尺寸,如果是内容是3列,那么这里返回3.否则返回1 ,
  2. 设置ItemDecoration 用getItemOffsets 控制间隔 ,
  3. 设置ItemDecoration 用public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
int spanSize = layoutManager.getSpanSizeLookup().getSpanSize(childAdapterPosition);

主要用于判断当前组是不是0,最后一组我用的另外的方法,组0 index=0, 代表是头部,如果是标题就绘制整个,如果内容 index=0也绘制 ,额好像不需要用到spanGroupIndex我记得用到过得

int spanGroupIndex = layoutManager.getSpanSizeLookup().getSpanGroupIndex(childAdapterPosition, spanCount);
int spanIndex = layoutManager.getSpanSizeLookup().getSpanIndex(childAdapterPosition, spanCount); //比如第一个是标题 ,第二列是 3格子,标题的永远是0 ,分3列的则是0 12 这样的循环。groupindex就是 每一列的完毕  就算一组。

用于判断是否是最后一行

int itemCount = parent.getLayoutManager().getItemCount();

用于预测下一个是不是标题,是标题那么现在就应该开始绘制下半身的圆角,以及如果内容item列不满足总列数,就绘制弥补空白处.

int lastspanIndex = layoutManager.getSpanSizeLookup().getSpanIndex(itemCount-1, spanCount); //比如第一个是标题 ,第二列是 3格子,标题的永远是0 ,分3列的则是0 12 这样的循环。groupindex就是 每一列的完毕  就算一组。

下面是具体写完之后的代码.

绘制空缺块和圆角块.
下图红色代表填充的空缺快,最后一组的填充则是绿色 , 头部是蓝色圆角 , 非最后一组底部圆角填充了黄色,我这样做只是为了调试,弄完之后我就把颜色改成白色了..
经常用到的判断
判断当前是跨了几行,用于判断是否是标题

GridLayoutManager layoutManager = new GridLayoutManager(recyclerView.getContext(), spanCount, LinearLayoutManager.VERTICAL, false);recyclerView.setLayoutManager(layoutManager);layoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {@Overridepublic int getSpanSize(int position) {int type = recyclerView.getAdapter().getItemViewType(position);if (position >= recyclerView.getAdapter().getItemCount()) {return NOT_FOUND_SPAN_SIZE;} else if (type == TYPE_MENU_GROUP_NAME) {return MENU_TITLE_SPAN_SIZE;} else if (type == TYPE_GROUP_DATA) {return 1;} else {return NOT_FOUND_SPAN_SIZE;//这是 decoration调用的。}}@Overridepublic int getSpanIndex(int position, int spanCount) {int spanIndex = super.getSpanIndex(position, spanCount);Log.w(TAG, "spanIndex" + spanIndex + ",pos" + position + ",spanCount:" + spanCount);return spanIndex;}@Overridepublic int getSpanGroupIndex(int adapterPosition, int spanCount) {int spanGroupIndex = super.getSpanGroupIndex(adapterPosition, spanCount);Log.w(TAG, "spanGroupIndex" + spanGroupIndex + ",adapterPosition" + adapterPosition + ",spanCount:" + spanCount);return spanGroupIndex;}});

绘制圆角和空缺快设置代码

for (int ix = 0; ix < childCount; ix++) {final View child = parent.getChildAt(ix);int position = parent.getChildAdapterPosition(child);GridLayoutManager layoutManager = (GridLayoutManager) parent.getLayoutManager();int spanCount = layoutManager.getSpanCount();//表示整个列表分多少列int spanSize = layoutManager.getSpanSizeLookup().getSpanSize(position);//表示当前格所占有的格子数int spanIndex = layoutManager.getSpanSizeLookup().getSpanIndex(position, spanCount); //这里参数是spanCount,不是spanSize,否则不对,比如第一个是标题 ,第二列是 3格子,标题的永远是0 ,分3列的则是0 12 这样的循环。groupindex就是 每一列的完毕  就算一组。if (BuildConfig.DEBUG) {
//                MyAppListAdapter adapter = (MyAppListAdapter) parent.getAdapter();
//                SubMenuItemI subMenuItemI = adapter.getData().get(position);
//                int spanSizeNext = layoutManager.getSpanSizeLookup().getSpanSize(position + 1);}if (spanSize != MENU_TITLE_SPAN_SIZE) {//普通item只会跨1个。 除非是菜单int spanGroupIndex = layoutManager.getSpanSizeLookup().getSpanGroupIndex(position, spanCount);int spanSizeNext = layoutManager.getSpanSizeLookup().getSpanSize(position + 1);if (spanIndex < MENU_TITLE_SPAN_SIZE - 1) {// MENU_TITLE_SPAN_SIZE 等于new GridManager里面的Count,这里用合并的数来判断也可以做,是否属于最后一个格子,但是最后一个格子又是否铺满整个屏幕是最后一个但是没有刚好没铺满,就把它给铺满。if (spanSizeNext == NOT_FOUND_SPAN_SIZE || spanSizeNext == MENU_TITLE_SPAN_SIZE) {//如果下一个不存在那么是最后一个,或者下一个是标题了。drawable = generateDrawable(-1);//补空缺boundAndDraw(c, child.getRight(), right, drawable, child.getTop(), child.getBottom());//这里没有任何圆角if (BuildConfig.DEBUG) {/*                MyAppListAdapter adapter = (MyAppListAdapter) parent.getAdapter();SubMenuItemI subMenuItemI = adapter.getData().get(position);Log.w(TAG, subMenuItemI + ",为最后一个前后面超出!spanIndex:" + spanIndex + ",spanSize:" + spanSize + ",height:" + child.getHeight());*/}}}if (spanSizeNext == NOT_FOUND_SPAN_SIZE || spanSizeNext == MENU_TITLE_SPAN_SIZE) {// 刚好铺满的那种 铺满还需要判断是否下一行是否是标题.//左下角圆角.drawable = generateDrawable(5);//,spanSizeNext == NOT_FOUND_SPAN_SIZE ?Color.GREEN:Color.YELLOW);int top = child.getTop() + child.getHeight();int bottom = (int) (top + radius);
//                            Log.w(TAG,"LEFT:"+left+",top:"+top+",right:"+right+",bottom:"+bottom);boundAndDraw(c, left, right, drawable, top, bottom);}if( spanGroupIndex==0&&position==0){//没有头部 的顶drawable = generateDrawable(4);int top = (int) (child.getTop() - radius);int bottom = child.getTop();boundAndDraw(c, left, right, drawable, top, bottom);}} else {//标题头drawable = generateDrawable(4);int top = (int) (child.getTop() - radius);int bottom = child.getTop();boundAndDraw(c, left, right, drawable, top, bottom);}}}private void debugDrwa(Canvas c, int left, int right, View child) {//以下计算主要用来确定绘制的位置final int top1 = child.getBottom() + 1;ColorDrawable drawable1 = new ColorDrawable(Color.BLUE);final int bottom = top1 + drawable1.getIntrinsicHeight();boundAndDraw(c, left, right, drawable1, top1, bottom);}/*** /外矩形 0左上、1右上、2 右下、3左下的圆角半 4 上 左和右边 5 ,下 左右。** @param type* @return*/private GradientDrawable generateDrawable(int type, int color) {this.color = color;return generateDrawable(type);}

测距代码 测距就是给view留空间,不留空间就绘制在一坨了.

int childAdapterPosition = parent.getChildAdapterPosition(view);GridLayoutManager layoutManager = (GridLayoutManager) parent.getLayoutManager();int spanCount = layoutManager.getSpanCount(); //构造时传递的参数.//DefaultSpanSizeLookupint spanSize = layoutManager.getSpanSizeLookup().getSpanSize(childAdapterPosition);int spanGroupIndex = layoutManager.getSpanSizeLookup().getSpanGroupIndex(childAdapterPosition, spanCount);if (spanSize == MENU_TITLE_SPAN_SIZE) { //标题才跨 3个。
//            if (needTop) {if (spanGroupIndex == 0) {outRect.top = (int) (getSpace() + radius);} else {outRect.top = (int) (getSpace() + (radius*2));}
//            }} else  {outRect.top = 0;outRect.left = 0;outRect.right = 0;if( spanGroupIndex==0){//没有头部 的顶outRect.top = (int) (getSpace()  + radius);}else{outRect.top = 0;}int spanIndex = layoutManager.getSpanSizeLookup().getSpanIndex(childAdapterPosition, spanCount); //比如第一个是标题 ,第二列是 3格子,标题的永远是0 ,分3列的则是0 12 这样的循环。groupindex就是 每一列的完毕  就算一组。int itemCount = parent.getLayoutManager().getItemCount();int lastspanIndex = layoutManager.getSpanSizeLookup().getSpanIndex(itemCount-1, spanCount); //比如第一个是标题 ,第二列是 3格子,标题的永远是0 ,分3列的则是0 12 这样的循环。groupindex就是 每一列的完毕  就算一组。if (childAdapterPosition>=itemCount-(lastspanIndex+1)) {//最后一行outRect.bottom= (int) (getSpace()+(radius/2));if(lastspanIndex==spanIndex&&(1+spanIndex!=MENU_TITLE_SPAN_SIZE)){
//                        outRect.right=30;//=parent.getRight()-parent.getPaddingRight();//写不写其实都一样,因为不绘制右边?不,应该说都铺满屏幕了,不怕控件没给够}//不能加right,会影响空间}}if (BuildConfig.DEBUG) {
//            int spanGroupIndex =;//1 23格子 或者 1列 都算一组,int spanIndex = layoutManager.getSpanSizeLookup().getSpanIndex(childAdapterPosition, spanCount); //比如第一个是标题 ,第二列是 3格子,标题的永远是0 ,分3列的则是0 12 这样的循环。groupindex就是 每一列的完毕  就算一组。/*       SubMenuItemI subMenuItemI = ((MyAppListAdapter) parent.getAdapter()).getData().get(childAdapterPosition);String title = subMenuItemI.getTitle();*/Log.w(TAG, "Decoration SpanIndex:" + spanIndex + ",groupindex:" + spanGroupIndex + ",spanSize:" + spanSize + ",model:" + "title" + ",adapterposition:" + childAdapterPosition);}

这篇关于[原创]recyclerview实现多行分组 给分组块加圆角.的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/959027

相关文章

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

hdu1043(八数码问题,广搜 + hash(实现状态压缩) )

利用康拓展开将一个排列映射成一个自然数,然后就变成了普通的广搜题。 #include<iostream>#include<algorithm>#include<string>#include<stack>#include<queue>#include<map>#include<stdio.h>#include<stdlib.h>#include<ctype.h>#inclu

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

【Prometheus】PromQL向量匹配实现不同标签的向量数据进行运算

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全栈,前后端开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi

让树莓派智能语音助手实现定时提醒功能

最初的时候是想直接在rasa 的chatbot上实现,因为rasa本身是带有remindschedule模块的。不过经过一番折腾后,忽然发现,chatbot上实现的定时,语音助手不一定会有响应。因为,我目前语音助手的代码设置了长时间无应答会结束对话,这样一来,chatbot定时提醒的触发就不会被语音助手获悉。那怎么让语音助手也具有定时提醒功能呢? 我最后选择的方法是用threading.Time

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo

C#实战|大乐透选号器[6]:实现实时显示已选择的红蓝球数量

哈喽,你好啊,我是雷工。 关于大乐透选号器在前面已经记录了5篇笔记,这是第6篇; 接下来实现实时显示当前选中红球数量,蓝球数量; 以下为练习笔记。 01 效果演示 当选择和取消选择红球或蓝球时,在对应的位置显示实时已选择的红球、蓝球的数量; 02 标签名称 分别设置Label标签名称为:lblRedCount、lblBlueCount

Kubernetes PodSecurityPolicy:PSP能实现的5种主要安全策略

Kubernetes PodSecurityPolicy:PSP能实现的5种主要安全策略 1. 特权模式限制2. 宿主机资源隔离3. 用户和组管理4. 权限提升控制5. SELinux配置 💖The Begin💖点点关注,收藏不迷路💖 Kubernetes的PodSecurityPolicy(PSP)是一个关键的安全特性,它在Pod创建之前实施安全策略,确保P

工厂ERP管理系统实现源码(JAVA)

工厂进销存管理系统是一个集采购管理、仓库管理、生产管理和销售管理于一体的综合解决方案。该系统旨在帮助企业优化流程、提高效率、降低成本,并实时掌握各环节的运营状况。 在采购管理方面,系统能够处理采购订单、供应商管理和采购入库等流程,确保采购过程的透明和高效。仓库管理方面,实现库存的精准管理,包括入库、出库、盘点等操作,确保库存数据的准确性和实时性。 生产管理模块则涵盖了生产计划制定、物料需求计划、

C++——stack、queue的实现及deque的介绍

目录 1.stack与queue的实现 1.1stack的实现  1.2 queue的实现 2.重温vector、list、stack、queue的介绍 2.1 STL标准库中stack和queue的底层结构  3.deque的简单介绍 3.1为什么选择deque作为stack和queue的底层默认容器  3.2 STL中对stack与queue的模拟实现 ①stack模拟实现