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

  • 3、创建一个 StarAdapter

  • 4、Activity 完整代码

  • 二、吸顶功能实现

    • 1、自定义 ItemDecoration
  • 2、StarDecoration 初始化

  • 3、重写 getItemOffsets() 方法

  • 4、绘制头部预留空间

  • 5、重写 onDraw() 绘制头部

  • 6、绘制吸顶效果

  • 7、StarDecoration 完整代码

  • 总结


前言

================================================================

使用纯代码 加 注释的方式,可以更快的理解源码

如果你喜欢,请点个赞,后期会不断的深入讲解


一、吸顶效果准备工作

========================================================================

在绘制吸顶效果之前,需要先实现一个RecyclerView功能列表

1、创建item,和item 实现


新建一个item 的Layout 文件

<?xml version="1.0" encoding="utf-8"?>

<RelativeLayout xmlns:android=“http://schemas.android.com/apk/res/android”

xmlns:tools=“http://schemas.android.com/tools”

android:layout_width=“match_parent”

android:layout_height=“match_parent”>

<TextView

android:id=“@+id/user_name”

android:text=“姓名”

android:gravity=“center”

android:layout_width=“match_parent”

android:layout_height=“44dp”

android:textSize=“20sp”

tools:ignore=“MissingConstraints” />

RecyclerView 中引用item

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android=“http://schemas.android.com/apk/res/android”

xmlns:app=“http://schemas.android.com/apk/res-auto”

xmlns:tools=“http://schemas.android.com/tools”

android:layout_width=“match_parent”

android:layout_height=“match_parent”

tools:context=“.MainActivity”>

<androidx.recyclerview.widget.RecyclerView

android:id=“@+id/main_rv”

android:layout_width=“match_parent”

android:layout_height=“match_parent”

tools:listitem=“@layout/item”

/>

2、创建一个 Star


public class Star {

String userName;

String groupName;

public String getUserName() {

return userName;

}

public void setUserName(String userName) {

this.userName = userName;

}

public String getGroupName() {

return groupName;

}

public void setGroupName(String groupName) {

this.groupName = groupName;

}

public Star(String userName, String groupName) {

this.userName = userName;

this.groupName = groupName;

}

}

3、创建一个 StarAdapter


在StarAdapter 中实现 RecyclerView 功能

public class StarAdapter extends RecyclerView.Adapter<StarAdapter.StarViewHolder> {

private Context mContext;

private List starList;

private LayoutInflater inflater;

public StarAdapter(Context context, List stars){

this.mContext = context;

this.starList = stars;

this.inflater = LayoutInflater.from(mContext);

}

@NonNull

@Override

public StarViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {

View view = inflater.inflate(R.layout.item, null);

return new StarViewHolder(view);

}

@Override

public void onBindViewHolder(@NonNull StarViewHolder holder, int position) {

holder.textView.setText(starList.get(position).getUserName());

if (position %2 == 0){

holder.textView.setBackgroundColor(Color.YELLOW);

}else {

holder.textView.setBackgroundColor(Color.RED);

}

}

@Override

public int getItemCount() {

return starList.size();

}

public class StarViewHolder extends RecyclerView.ViewHolder {

private TextView textView;

public StarViewHolder(@NonNull View itemView) {

super(itemView);

textView = itemView.findViewById(R.id.user_name);

}

}

}

4、Activity 完整代码


public class MainActivity extends AppCompatActivity {

private RecyclerView recyclerView;

private StarAdapter starAdapter;

private List starList;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

init();

recyclerView = findViewById(R.id.main_rv);

starAdapter = new StarAdapter(this, starList);

recyclerView.setLayoutManager(new LinearLayoutManager(this));

recyclerView.setAdapter(starAdapter);

}

private void init(){

starList = new ArrayList<>();

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

for (int j = 0; j < 20; j++) {

if (i % 2 ==0){

starList.add(new Star(“小明” + j, “快乐家族” + i));

}else {

starList.add(new Star(“王美丽” + j, “嗨嗨家族” + i));

}

}

}

}

}

上面源码中,我写了一个嵌套的for 循环,用来实现数据的赋值,显示为4组,每组组20条数据。代码运行效果如下:

在这里插入图片描述

二、吸顶功能实现

======================================================================

1、自定义 ItemDecoration


StarDecoration 中,我写了一个分辩率的转换方法

public class StarDecoration extends RecyclerView.ItemDecoration {

/**

  • 分辩率

  • @param context

  • @param dpValue

  • @return

*/

private int dp2px(Context context, float dpValue){

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

context.getResources().getDisplayMetrics());

}

}

2、StarDecoration 初始化


// 分组栏的高度

private int headerHeight;

private int valueHeight = 50;

private Paint headPaint;

private Paint drawTextPaint;

private Rect textRect;

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();

}

3、重写 getItemOffsets() 方法


ItemDecoration 想要绘制的话,就必须得重写 getItemOffsets() 方法。代码如下

@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);

// 分割线预留的空间

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

}

}

上面的代码中,我们给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();

最后

针对于上面的问题,我总结出了互联网公司Android程序员面试涉及到的绝大部分面试题及答案,并整理做成了文档,以及系统的进阶学习视频资料。
(包括Java在Android开发中应用、APP框架知识体系、高级UI、全方位性能调优,NDK开发,音视频技术,人工智能技术,跨平台技术等技术资料),希望能帮助到你面试前的复习,且找到一个好的工作,也节省大家在网上搜索资料的时间来学习。
Android进阶视频+面试资料部分截图

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

(StarAdapter) parent.getAdapter();

// 当前屏幕上展示的

int count = parent.getChildCount();

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

int left = parent.getPaddingLeft();

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

最后

针对于上面的问题,我总结出了互联网公司Android程序员面试涉及到的绝大部分面试题及答案,并整理做成了文档,以及系统的进阶学习视频资料。
(包括Java在Android开发中应用、APP框架知识体系、高级UI、全方位性能调优,NDK开发,音视频技术,人工智能技术,跨平台技术等技术资料),希望能帮助到你面试前的复习,且找到一个好的工作,也节省大家在网上搜索资料的时间来学习。
[外链图片转存中…(img-wWcpLW7h-1714329322085)]

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值