RecyclerView实现混合布局
PS:好长时间不写博客了,起初是不知道写些什么,后来接触了到了很多东西,原本看似简单的东西,背后都隐藏着巨大的秘密,想handler的使用,一般情况下会引起内存泄漏问题,想着找到方法结局不就得了吗,可是谁想查阅资料发现,这个东西没想到牵扯的这么深, Activity -> handler -> message -> queue -> UI线程作为GC Root引用链,看都看懵逼了,赶紧看一些稍微简单的UI 实现,突发奇想,RecyclerView的混合布局界面的实现。如下图
。。。
像这些布局,可以用listview来实现,也可以RecyclerView来实现,每个布局文件都是不一样的,第一张图:上面是一行三个图,下面是一行四个图。第二张图一行分左右。作为一个新手来说,估计就有点难以招架了,不过用recyclerview就比较好实现了,只要指定Type,来加载不同的布局就可以。下面来简单实现一个简单点的。有一行两个数据,有一行一个数据界面。
我们可以看到,这个RecyclerView中有多种item显示出来,那么具体怎么实现呢,其实在RecyclerView中,我们可以重写方法getItemViewType(),这个方法会传进一个参数position表示当前是第几个Item,然后我们可以通过position拿到当前的Item对象,然后判断这个item对象需要那种视图,返回一个int类型的视图标志,然后在onCreatViewHolder方法中给引入布局,这样就能够实现多种item显示了,我们先来看一下,一共要实现多少方法,他们分别是什么,我都加了注释。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | /** * 加载视图 * */ @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { return null ; } /** * 加载数据 * */ @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { } /** * 返回数据数量 * */ @Override public int getItemCount() { return 0 ; } /** * 返回数据类型 * */ @Override public int getItemViewType( int position) { return super .getItemViewType(position); } |
1:Item xml布局文件和Bean类,ViewHolder创建。
注:bean因demo简洁,并没有用到bean类。一共两个布局,这里只给出一个,类似写出即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | <LinearLayout xmlns:android= "http://schemas.android.com/apk/res/android" android:layout_width= "match_parent" android:layout_height= "wrap_content" > <TextView android:layout_width= "match_parent" android:layout_height= "50dp" android:gravity= "center" android:background= "@color/colorPrimary" android:id= "@+id/id_one_tv1" /> </LinearLayout> public class TypeViewHolderOne extends RecyclerView.ViewHolder { public TextView textView; public TypeViewHolderOne(View itemView) { super (itemView); textView = itemView.findViewById(R.id.id_one_tv1); } } |
2:方法讲解
注意:一般情况下后台会给移动端返回一串JSON字符串,里面有一些数据是需要自己来专门挑出来的,
方法:
- 你可以写多个list来存放不同的数据,但是如果是多个的话,返回的数据就一串字符串,你不仅要挑出来,还要存放在多个list里面,下次下拉刷新时还要在多个list中累加数据,这样就有点麻烦了
- 不挑出来直接就只判断type,然后根据type去调用不同的layout,然后在绑定数据的方法中再次判断是不是自己想要的ViewHolder,最后赋值显示。
返回type类型方法
1 2 3 4 5 | //返回类型,有单列显示还是双列显示 @Override public int getItemViewType( int position) { return mList.get(position).getType(); } |
我们重写了getItemViewType()方法后,就要写不同的item(布局文件),然后在onCreatViewHolder方法引入布局。这里的类型就简单直接写的1和2。
1 2 3 4 5 6 7 8 9 10 11 12 13 | @NonNull @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { //视图显示 //创建view视图 switch (viewType) { case 1 : return new TypeViewHolderOne(layoutInflater.inflate(R.layout.model_view1, parent, false )); case 2 : return new TypeViewHolderTwo(layoutInflater.inflate(R.layout.model_view2, parent, false )); } return null ; } |
我们看到的TypeViewHolderOne(View view);这个方法是自定义的需要继承RecyclerView.ViewHolder
1 2 3 4 5 6 7 | public class TypeViewHolderOne extends RecyclerView.ViewHolder { public TextView textView; public TypeViewHolderOne(View itemView) { super (itemView); textView = itemView.findViewById(R.id.id_one_tv1); } } |
写到这里,布局有了,viewholder有了,数据的判断类型有了,就差展示了,所以重写onBindViewHolder方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | /** * 方法作用:绑定数据, * 方法描述:根据holder对控件进行赋值,同时如果有回调接口,在该方法中写。 */ @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { //优化 绑定数据 if (holder instanceof TypeViewHolderOne){ //判断是哪个对象 TypeViewHolderOne viewHolderOne= (TypeViewHolderOne) holder; viewHolderOne.textView.setText(mList.get(position).getName()); } else if (holder instanceof TypeViewHolderTwo){ TypeViewHolderTwo viewHolderTwo= (TypeViewHolderTwo) holder; viewHolderTwo.textView1.setText(mList.get(position).getName()); viewHolderTwo.textView2.setText( "类型" +mList.get(position).getType()); } } |
所有预备工作已经做完了,开始赋值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | recyclerViewAdapter = new RecyclerViewAdapter2( this , list); recyclerView.setAdapter(recyclerViewAdapter); //本地模拟数据 public void addData() { int a=( int )(Math.random()* 10 ); TypeBean typeBean; for ( int i = 0 ; i < 10 ; i++) { typeBean = new TypeBean(); typeBean.setName( "样式:" + (i + 1 )); typeBean.setType( 1 ); if (i == a) { typeBean.setType( 2 ); } list.add(typeBean); } recyclerViewAdapter.notifyDataSetChanged(); } |
现在还不能运行,因为还没有给recyclerview指定一个布局格式,下面是指定了布局格式,一共两列,获取一开始咱们设置的type,如果type=2,则要让他独自占2列,也就是说,他自己一行。
1 2 3 4 5 6 7 8 9 10 11 | final GridLayoutManager gridLayoutManager = new GridLayoutManager( this , 2 ); gridLayoutManager.setSpanSizeLookup( new GridLayoutManager.SpanSizeLookup() { @Override public int getSpanSize( int position) { int itemViewType = recyclerView.getAdapter().getItemViewType(position); if (itemViewType == 2 ) { return 2 ; } return 1 ; } }); |
装饰可写可不写
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | //设置各个item的装饰,如间距,大小等,可写可不写,不写可以在xml文件中设置。 recyclerView.addItemDecoration( new RecyclerView.ItemDecoration() { @Override public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { //super.getItemOffsets(outRect, view, parent, state); //拿到Grid管理器 GridLayoutManager.LayoutParams layoutParams = (GridLayoutManager.LayoutParams) view.getLayoutParams(); //拿到grid管理器所设置的总列数 int spanSize = layoutParams.getSpanSize(); //拿到当前所在列数 int spanIndex = layoutParams.getSpanIndex(); //设置顶部间距 outRect.top = 20 ; if (spanSize != gridLayoutManager.getSpanCount()) { if (spanIndex == 1 ) { outRect.left = 10 ; } else { outRect.right = 10 ; } } } }); recyclerView.setLayoutManager(gridLayoutManager); |
现在运行试试吧
总结:
1:使用RecyclerView必须要写的就是适配器要继承RecyclerView.Adapter<RecyclerView.ViewHolder>,当然这里面你也可以自定义。
2:加载多个布局文件时(item)需要加入Type字段去判断是哪一个item。在activity中加载recyclerview时,要加入布局样式,比如说,普通的LinearLayoutManager,或者GridLayoutManager,StaggeredGridLayoutManager
。不加是不显示的。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)