Android 自定义UI 实战 03 RecyclerView 吸顶 仿微信好友列表

上面的代码中,我们给ItemDecoration 预留了一个划线的空间

运行如下:

在这里插入图片描述

4、绘制头部预留空间


  1. 在Adapter 中判断当前组的第一个item 是不是头部

// 是否是组的第一个Item

public boolean isFirstItemOfGroup(int position) {

if (position == 0) {

return true;

} else {

// 拿到当前位置的和前一个位置的 组名

String currentItemGroupName = getGroupName(position);

String preItemGroupName = getGroupName(position - 1);

// 如果相等,则表示position 的 item 不是第一个,否则是

if (currentItemGroupName.equals(preItemGroupName)) {

return false;

} else {

return true;

}

}

}

  1. 在 获取到头部 item 之后,预留一个绘制空间

// 判断 Item 是头部

boolean isGroupHeader = starAdapter.isFirstItemOfGroup(position);

if (isGroupHeader){

// headerHeight 是头部 Item 的高度

outRect.set(0, headerHeight, 0, 0);

}else {

// decorationTop 分割线的高度

outRect.set(0, decorationTop, 0, 0);

}

getItemOffsets() 中添加上面代码后,预留的 item 的头部空间就出来了,运行如下

在这里插入图片描述

5、重写 onDraw() 绘制头部


// 绘制自己

@Override

public void onDraw(@NonNull Canvas c, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {

super.onDraw(c, parent, state);

if (parent.getAdapter() instanceof StarAdapter){

StarAdapter starAdapter = (StarAdapter) parent.getAdapter();

// 当前屏幕上展示的

int count = parent.getChildCount();

// 实现 itemView 的宽度和分割线的宽度一样

int left = parent.getPaddingLeft();

int right = parent.getWidth() - parent.getPaddingLeft();

for (int i = 0; i < count; i++) {

View view = parent.getChildAt(i);

// 当前item 的位置

int position = parent.getChildLayoutPosition(view);

// 判断是否是头部

boolean isGroupHeader = starAdapter.isFirstItemOfGroup(position);

if (isGroupHeader){

c.drawRect(left, view.getTop() - headerHeight, right, view.getTop(), headPaint);

// 获取当前组名

String groupName = starAdapter.getGroupName(position);

c.drawText(groupName,left + groupNameLeftPadding,

view.getTop() - headerHeight / 2 + textRect.height() / 2,

drawTextPaint);

}else {

c.drawRect(left, view.getTop() - valueHeight, right, view.getTop(), headPaint);

}

}

}

}

代码运行结果如下:

在这里插入图片描述

6、绘制吸顶效果


// 绘制吸顶效果

@Override

public void onDrawOver(@NonNull Canvas c, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {

super.onDrawOver(c, parent, state);

if (parent.getAdapter() instanceof StarAdapter){

StarAdapter starAdapter = (StarAdapter) parent.getAdapter();

int left = parent.getPaddingLeft();

int right = parent.getRight();

int top = parent.getTop();

// 当前显示在界面的第一个 item

int position = ((LinearLayoutManager)parent.getLayoutManager()).findFirstVisibleItemPosition();

View itemView = parent.findViewHolderForAdapterPosition(position).itemView;

// 获取当前的上一个 头部 item

boolean isFirstItemOfGroup = starAdapter.isFirstItemOfGroup(position +1 );

if(isFirstItemOfGroup){

int bottom = Math.min(top + headerHeight, itemView.getBottom());

c.drawRect(left, top, right, bottom, headPaint);

String groupName = starAdapter.getGroupName(position);

drawTextPaint.getTextBounds(groupName, 0, groupName.length(), textRect);

c.clipRect(left, top, right, bottom);

c.drawText(groupName, left + 20,

bottom - headerHeight / 2 + textRect.height() / 2, drawTextPaint);

}else {

// 固定的头部信息

c.drawRect(left, top, right, top + headerHeight, headPaint);

String groupName = starAdapter.getGroupName(position);

drawTextPaint.getTextBounds(groupName, 0, groupName.length(), textRect);

// 绘制文字

c.drawText(groupName, left + 20, top + headerHeight / 2 + textRect.height() /2, drawTextPaint);

}

}

}

运行结果如下:

在这里插入图片描述

7、StarDecoration 完整代码


public class StarDecoration extends RecyclerView.ItemDecoration {

// 分组栏的高度

private int headerHeight;

private int valueHeight = 50;

private Paint headPaint;

private Paint drawTextPaint;

private Rect textRect;

private int decorationTop = 4;

// 组名的 padding

private int groupNameLeftPadding = 20;

public StarDecoration(Context context){

// 顶部吸顶栏的高度

headerHeight = dp2px(context, valueHeight);

// 每一组的头部的Paint

headPaint = new Paint();

headPaint.setColor(Color.RED);

drawTextPaint = new Paint();

drawTextPaint.setColor(Color.YELLOW);

drawTextPaint.setTextSize(50);

textRect = new Rect();

}

// 绘制自己

@Override

public void onDraw(@NonNull Canvas c, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {

super.onDraw(c, parent, state);

if (parent.getAdapter() instanceof StarAdapter){

StarAdapter starAdapter = (StarAdapter) parent.getAdapter();

// 当前屏幕上展示的

int count = parent.getChildCount();

// 实现 itemView 的宽度和分割线的宽度一样

int left = parent.getPaddingLeft();

int right = parent.getWidth() - parent.getPaddingLeft();

for (int i = 0; i < count; i++) {

View view = parent.getChildAt(i);

// 当前item 的位置

int position = parent.getChildLayoutPosition(view);

// 判断是否是头部

boolean isGroupHeader = starAdapter.isFirstItemOfGroup(position);

if (isGroupHeader){

c.drawRect(left, view.getTop() - headerHeight, right, view.getTop(), headPaint);

// 获取当前组名

String groupName = starAdapter.getGroupName(position);

c.drawText(groupName,left + groupNameLeftPadding,

view.getTop() - headerHeight / 2 + textRect.height() / 2,

drawTextPaint);

}else {

c.drawRect(left, view.getTop() - decorationTop, right, view.getTop(), headPaint);

}

}

}

}

// 绘制吸顶效果

@Override

public void onDrawOver(@NonNull Canvas c, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {

super.onDrawOver(c, parent, state);

if (parent.getAdapter() instanceof StarAdapter){

StarAdapter starAdapter = (StarAdapter) parent.getAdapter();

int left = parent.getPaddingLeft();

int right = parent.getRight();

int top = parent.getTop();

// 当前显示在界面的第一个 item

int position = ((LinearLayoutManager)parent.getLayoutManager()).findFirstVisibleItemPosition();

View itemView = parent.findViewHolderForAdapterPosition(position).itemView;

// 获取当前的上一个 头部 item

boolean isFirstItemOfGroup = starAdapter.isFirstItemOfGroup(position +1 );

if(isFirstItemOfGroup){

int bottom = Math.min(top + headerHeight, itemView.getBottom());

c.drawRect(left, top, right, bottom, headPaint);

String groupName = starAdapter.getGroupName(position);

drawTextPaint.getTextBounds(groupName, 0, groupName.length(), textRect);

c.clipRect(left, top, right, bottom);

c.drawText(groupName, left + 20,

bottom - headerHeight / 2 + textRect.height() / 2, drawTextPaint);

}else {

// 固定的头部信息

c.drawRect(left, top, right, top + headerHeight, headPaint);

String groupName = starAdapter.getGroupName(position);

drawTextPaint.getTextBounds(groupName, 0, groupName.length(), textRect);

// 绘制文字

c.drawText(groupName, left + 20, top + headerHeight / 2 + textRect.height() /2, drawTextPaint);

}

}

}

@Override

public void getItemOffsets(@NonNull Rect outRect, @NonNull View view,

@NonNull RecyclerView parent, @NonNull RecyclerView.State state) {

super.getItemOffsets(outRect, view, parent, state);

// 绑定自己的 Adapter

if (parent.getAdapter() instanceof StarAdapter){

StarAdapter starAdapter = (StarAdapter) parent.getAdapter();

// 当前item 的位置

int position = parent.getChildLayoutPosition(view);

// 判断 Item 是头部

boolean isGroupHeader = starAdapter.isFirstItemOfGroup(position);

if (isGroupHeader){

// headerHeight 是头部 Item 的高度

outRect.set(0, headerHeight, 0, 0);

}else {

// decorationTop 分割线的高度

outRect.set(0, decorationTop, 0, 0);

}

}

}

/**

  • 分辩率

  • @param context

  • @param dpValue

  • @return

*/

private int dp2px(Context context, float dpValue){

return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpValue,

context.getResources().getDisplayMetrics());

}

}

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
img

学习分享

在当下这个信息共享的时代,很多资源都可以在网络上找到,只取决于你愿不愿意找或是找的方法对不对了

很多朋友不是没有资料,大多都是有几十上百个G,但是杂乱无章,不知道怎么看从哪看起,甚至是看后就忘

如果大家觉得自己在网上找的资料非常杂乱、不成体系的话,我也分享一套给大家,比较系统,我平常自己也会经常研读。

2021最新上万页的大厂面试真题

七大模块学习资料:如NDK模块开发、Android框架体系架构…

只有系统,有方向的学习,才能在段时间内迅速提高自己的技术。

这份体系学习笔记,适应人群:
**第一,**学习知识比较碎片化,没有合理的学习路线与进阶方向。
**第二,**开发几年,不知道如何进阶更进一步,比较迷茫。
**第三,**到了合适的年纪,后续不知道该如何发展,转型管理,还是加强技术研究。

由于文章内容比较多,篇幅不允许,部分未展示内容以截图方式展示 。

本文已被CODING开源项目:《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》收录

一个人可以走的很快,但一群人才能走的更远。如果你从事以下工作或对以下感兴趣,欢迎戳这里加入程序员的圈子,让我们一起学习成长!

AI人工智能、Android移动开发、AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算

Android框架体系架构…**

[外链图片转存中…(img-SnbFiVXb-1712102032098)]

只有系统,有方向的学习,才能在段时间内迅速提高自己的技术。

这份体系学习笔记,适应人群:
**第一,**学习知识比较碎片化,没有合理的学习路线与进阶方向。
**第二,**开发几年,不知道如何进阶更进一步,比较迷茫。
**第三,**到了合适的年纪,后续不知道该如何发展,转型管理,还是加强技术研究。

由于文章内容比较多,篇幅不允许,部分未展示内容以截图方式展示 。

本文已被CODING开源项目:《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》收录

一个人可以走的很快,但一群人才能走的更远。如果你从事以下工作或对以下感兴趣,欢迎戳这里加入程序员的圈子,让我们一起学习成长!

AI人工智能、Android移动开发、AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值