当前位置:首页 > 科技  > 软件

RecyclerView中ItemDecoration的精妙用法,实现自定义分隔线、边距和背景效果

来源: 责编: 时间:2024-05-11 09:16:23 81观看
导读ItemDecoration 是 RecyclerView 组件的一个非常有用的功能,用于添加自定义的装饰项(如分隔线、边距、背景等)到 RecyclerView 的每个 item 之间或周围。recyclerView.addItemDecoration()ItemDecoration主要的三个方法:o

ItemDecoration 是 RecyclerView 组件的一个非常有用的功能,用于添加自定义的装饰项(如分隔线、边距、背景等)到 RecyclerView 的每个 item 之间或周围。ilt28资讯网——每日最新资讯28at.com

recyclerView.addItemDecoration()

ItemDecoration主要的三个方法:ilt28资讯网——每日最新资讯28at.com

  1. onDraw(Canvas c, RecyclerView parent, RecyclerView.State state): 在 RecyclerView 的 canvas 上绘制自定义的装饰项,通常用于绘制分隔线或背景。
  2. onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state): 与 onDraw 类似,但绘制的内容会出现在 item 的视图之上。在 item 视图上方绘制内容(如高亮或选择效果),可以使用这个方法。
  3. getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state): 设置 item 的边距。outRect 参数是一个 Rect 对象,可以设置它的 left、top、right 和 bottom 属性来定义 item 的额外空间。这些额外的空间会用于绘制分隔线或边距。

图片图片ilt28资讯网——每日最新资讯28at.com

  • 图1:代表了getItemOffsets(),可以实现类似padding的效果。
  • 图2:代表了onDraw(),可以实现类似绘制背景的效果,内容在上面。
  • 图3:代表了onDrawOver(),可以绘制在内容的上面,覆盖内容。

分割线

实现分割线效果需要 getItemOffsets()和 onDraw()2个方法,首先用 getItemOffsets给item下方空出一定高度的空间(例子中是1dp),然后用onDraw绘制这个空间。ilt28资讯网——每日最新资讯28at.com

public class SimpleDividerDecoration extends RecyclerView.ItemDecoration {    private int dividerHeight;    private Paint dividerPaint;    public SimpleDividerDecoration(Context context) {        dividerPaint = new Paint();        dividerPaint.setColor(context.getResources().getColor(R.color.colorAccent));        dividerHeight = context.getResources().getDimensionPixelSize(R.dimen.divider_height);    }    @Override    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {        super.getItemOffsets(outRect, view, parent, state);        outRect.bottom = dividerHeight;    }    @Override    public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {        int childCount = parent.getChildCount();        int left = parent.getPaddingLeft();        int right = parent.getWidth() - parent.getPaddingRight();        for (int i = 0; i < childCount - 1; i++) {            View view = parent.getChildAt(i);            float top = view.getBottom();            float bottom = view.getBottom() + dividerHeight;            c.drawRect(left, top, right, bottom, dividerPaint);        }    }}

图片图片ilt28资讯网——每日最新资讯28at.com

标签

标签都是覆盖在内容之上的,可以用onDrawOver()来实现,这里简单实现一个颜色标签。ilt28资讯网——每日最新资讯28at.com

public class LeftAndRightTagDecoration extends RecyclerView.ItemDecoration {    private int tagWidth;    private Paint leftPaint;    private Paint rightPaint;    public LeftAndRightTagDecoration(Context context) {        leftPaint = new Paint();        leftPaint.setColor(context.getResources().getColor(R.color.colorAccent));        rightPaint = new Paint();        rightPaint.setColor(context.getResources().getColor(R.color.colorPrimary));        tagWidth = context.getResources().getDimensionPixelSize(R.dimen.tag_width);    }    @Override    public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {        super.onDrawOver(c, parent, state);        int childCount = parent.getChildCount();        for (int i = 0; i < childCount; i++) {            View child = parent.getChildAt(i);            int pos = parent.getChildAdapterPosition(child);            boolean isLeft = pos % 2 == 0;            if (isLeft) {                float left = child.getLeft();                float right = left + tagWidth;                float top = child.getTop();                float bottom = child.getBottom();                c.drawRect(left, top, right, bottom, leftPaint);            } else {                float right = child.getRight();                float left = right - tagWidth;                float top = child.getTop();                float bottom = child.getBottom();                c.drawRect(left, top, right, bottom, rightPaint);            }        }    }}

图片图片ilt28资讯网——每日最新资讯28at.com

ItemDecoration组合

ItemDecoration是可以叠加的,可以将多个效果通过addItemDecoration方法叠加,将上面两种效果叠加。ilt28资讯网——每日最新资讯28at.com

recyclerView.addItemDecoration(new LeftAndRightTagDecoration(this));recyclerView.addItemDecoration(new SimpleDividerDecoration(this));

图片图片ilt28资讯网——每日最新资讯28at.com

Section分组

定义接口用来进行数据分组和获取首字母,重写getItemOffsets()和onDraw()方法,并根据数据进行分组处理。ilt28资讯网——每日最新资讯28at.com

public interface DecorationCallback {        long getGroupId(int position);        String getGroupFirstLine(int position);    }
public class SectionDecoration extends RecyclerView.ItemDecoration {    private static final String TAG = "SectionDecoration";    private DecorationCallback callback;    private TextPaint textPaint;    private Paint paint;    private int topGap;    private Paint.FontMetrics fontMetrics;    public SectionDecoration(Context context, DecorationCallback decorationCallback) {        Resources res = context.getResources();        this.callback = decorationCallback;        paint = new Paint();        paint.setColor(res.getColor(R.color.colorAccent));        textPaint = new TextPaint();        textPaint.setTypeface(Typeface.DEFAULT_BOLD);        textPaint.setAntiAlias(true);        textPaint.setTextSize(80);        textPaint.setColor(Color.BLACK);        textPaint.getFontMetrics(fontMetrics);        textPaint.setTextAlign(Paint.Align.LEFT);        fontMetrics = new Paint.FontMetrics();        topGap = res.getDimensionPixelSize(R.dimen.sectioned_top);//32dp    }    @Override    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {        super.getItemOffsets(outRect, view, parent, state);        int pos = parent.getChildAdapterPosition(view);        Log.i(TAG, "getItemOffsets:" + pos);        long groupId = callback.getGroupId(pos);        if (groupId < 0) return;        if (pos == 0 || isFirstInGroup(pos)) {//同组的第一个才添加padding            outRect.top = topGap;        } else {            outRect.top = 0;        }    }    @Override    public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {        super.onDraw(c, parent, state);        int left = parent.getPaddingLeft();        int right = parent.getWidth() - parent.getPaddingRight();        int childCount = parent.getChildCount();        for (int i = 0; i < childCount; i++) {            View view = parent.getChildAt(i);            int position = parent.getChildAdapterPosition(view);            long groupId = callback.getGroupId(position);            if (groupId < 0) return;            String textLine = callback.getGroupFirstLine(position).toUpperCase();            if (position == 0 || isFirstInGroup(position)) {                float top = view.getTop() - topGap;                float bottom = view.getTop();                c.drawRect(left, top, right, bottom, paint);//绘制红色矩形                c.drawText(textLine, left, bottom, textPaint);//绘制文本            }        }    }        private boolean isFirstInGroup(int pos) {        if (pos == 0) {            return true;        } else {            long prevGroupId = callback.getGroupId(pos - 1);            long groupId = callback.getGroupId(pos);            return prevGroupId != groupId;        }    }    public interface DecorationCallback {        long getGroupId(int position);        String getGroupFirstLine(int position);    }}
recyclerView.addItemDecoration(new SectionDecoration(this, new SectionDecoration.DecorationCallback() {    @Override    public long getGroupId(int position) {        return Character.toUpperCase(dataList.get(position).getName().charAt(0));    }    @Override    public String getGroupFirstLine(int position) {        return dataList.get(position).getName().substring(0, 1).toUpperCase();    }}));

StickyHeader

头部吸顶效果,header不动肯定是要绘制item内容之上,需要重写onDrawOver()方法,其和Section实现一样。ilt28资讯网——每日最新资讯28at.com

public class PinnedSectionDecoration extends RecyclerView.ItemDecoration {    private static final String TAG = "PinnedSectionDecoration";    private DecorationCallback callback;    private TextPaint textPaint;    private Paint paint;    private int topGap;    private Paint.FontMetrics fontMetrics;    public PinnedSectionDecoration(Context context, DecorationCallback decorationCallback) {        Resources res = context.getResources();        this.callback = decorationCallback;        paint = new Paint();        paint.setColor(res.getColor(R.color.colorAccent));        textPaint = new TextPaint();        textPaint.setTypeface(Typeface.DEFAULT_BOLD);        textPaint.setAntiAlias(true);        textPaint.setTextSize(80);        textPaint.setColor(Color.BLACK);        textPaint.getFontMetrics(fontMetrics);        textPaint.setTextAlign(Paint.Align.LEFT);        fontMetrics = new Paint.FontMetrics();        topGap = res.getDimensionPixelSize(R.dimen.sectioned_top);    }    @Override    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {        super.getItemOffsets(outRect, view, parent, state);        int pos = parent.getChildAdapterPosition(view);        long groupId = callback.getGroupId(pos);        if (groupId < 0) return;        if (pos == 0 || isFirstInGroup(pos)) {            outRect.top = topGap;        } else {            outRect.top = 0;        }    }    @Override    public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {        super.onDrawOver(c, parent, state);        int itemCount = state.getItemCount();        int childCount = parent.getChildCount();        int left = parent.getPaddingLeft();        int right = parent.getWidth() - parent.getPaddingRight();        float lineHeight = textPaint.getTextSize() + fontMetrics.descent;        long preGroupId, groupId = -1;        for (int i = 0; i < childCount; i++) {            View view = parent.getChildAt(i);            int position = parent.getChildAdapterPosition(view);            preGroupId = groupId;            groupId = callback.getGroupId(position);            if (groupId < 0 || groupId == preGroupId) continue;            String textLine = callback.getGroupFirstLine(position).toUpperCase();            if (TextUtils.isEmpty(textLine)) continue;            int viewBottom = view.getBottom();            float textY = Math.max(topGap, view.getTop());            if (position + 1 < itemCount) { //下一个和当前不一样移动当前                long nextGroupId = callback.getGroupId(position + 1);                if (nextGroupId != groupId && viewBottom < textY ) {//组内最后一个view进入了header                    textY = viewBottom;                }            }            c.drawRect(left, textY - topGap, right, textY, paint);            c.drawText(textLine, left, textY, textPaint);        }    }}

图片图片ilt28资讯网——每日最新资讯28at.com

ilt28资讯网——每日最新资讯28at.com

本文链接:http://www.28at.com/showinfo-26-87958-0.htmlRecyclerView中ItemDecoration的精妙用法,实现自定义分隔线、边距和背景效果

声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com

上一篇: 从简单中窥见高端,彻底搞懂任务可中断机制与任务插队机制

下一篇: 总结CSS中各个属性使用百分比(%)基准值

标签:
  • 热门焦点
  • K8S | Service服务发现

    K8S | Service服务发现

    一、背景在微服务架构中,这里以开发环境「Dev」为基础来描述,在K8S集群中通常会开放:路由网关、注册中心、配置中心等相关服务,可以被集群外部访问;图片对于测试「Tes」环境或者
  • 多线程开发带来的问题与解决方法

    多线程开发带来的问题与解决方法

    使用多线程主要会带来以下几个问题:(一)线程安全问题  线程安全问题指的是在某一线程从开始访问到结束访问某一数据期间,该数据被其他的线程所修改,那么对于当前线程而言,该线程
  • 这款新兴工具平台,让你的电脑效率翻倍

    这款新兴工具平台,让你的电脑效率翻倍

    随着信息技术的发展,我们获取信息的渠道越来越多,但是处理信息的效率却成为一个瓶颈。于是各种工具应运而生,都在争相解决我们的工作效率问题。今天我要给大家介绍一款效率
  • .NET 程序的 GDI 句柄泄露的再反思

    .NET 程序的 GDI 句柄泄露的再反思

    一、背景1. 讲故事上个月我写过一篇 如何洞察 C# 程序的 GDI 句柄泄露 文章,当时用的是 GDIView + WinDbg 把问题搞定,前者用来定位泄露资源,后者用来定位泄露代码,后面有朋友反
  • 东方甄选单飞:有些鸟注定是关不住的

    东方甄选单飞:有些鸟注定是关不住的

    文/彭宽鸿编辑/罗卿东方甄选创始人俞敏洪带队的&ldquo;7天甘肃行&rdquo;直播活动已在近日顺利收官。成立后一年多时间里,东方甄选要脱离抖音自立门户的传闻不绝于耳,&ldquo;7
  • 余承东:AI大模型技术的发展将会带来下一代智能终端操作系统的智慧体验

    余承东:AI大模型技术的发展将会带来下一代智能终端操作系统的智慧体验

    8月4日消息,2023年华为开发者大会(HDC.Together)今天正式开幕,华为发布HarmonyOS 4、全新升级的鸿蒙开发套件、HarmonyOS Next开发者预览版本等一系列
  • 2纳米决战2025

    2纳米决战2025

    集微网报道 从三强争霸到四雄逐鹿,2nm的厮杀声已然隐约传来。无论是老牌劲旅台积电、三星,还是誓言重回先进制程领先地位的英特尔,甚至初成立不久的新
  • 自研Exynos回归!三星Galaxy S24系列将提供Exynos和骁龙双版本

    自研Exynos回归!三星Galaxy S24系列将提供Exynos和骁龙双版本

    年初,全新的三星Galaxy S23系列发布,包含Galaxy S23、Galaxy S23+和Galaxy S23 Ultra三个版本,全系搭载超频版骁龙8 Gen 2,虽同样采用台积电4nm工艺制
  • Windows 11发布,微软一改往常对老机型开放的态度

    Windows 11发布,微软一改往常对老机型开放的态度

    距离 Windows 11 发布已经过去一周,在过去一周里,很多数码爱好者围绕其对 Android 应用的支持、对老机型的升级问题展开了激烈讨论。与以往不同的是,在这次大
Top