为RecyclerView的不同item项实现不同的布局(添加分类Header)

最近在做一个应用的时候,需要为GridLayoutManager添加头部header,然后自然而然就想到了用不同的itemType去加载不同的布局。

1.实现多item布局,用不同的itemType去加载不同的布局。

主要思路就是先定义好标识itemType的常量,然后重写getItemViewType()方法,根据不同的位置(position)返回不同的Type,接着在onCreateViewHolder()中根据参数viewType去判断该item项应该 inflate 哪个布局文件,并返回相应的ViewHolder实例(这里ViewHolder是根据不同的item布局预先自定义好的不同的ViewHolder)

比如我的代码:

 1 public class MyRecyclerCardviewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>{
 2
 3     public static enum ITEM_TYPE {
 4         ITEM_TYPE_Theme,
 5         ITEM_TYPE_Video
 6     }
 7     //数据集
 8     public List<Integer> mdatas;
 9     private TextView themeTitle;
10
11     public MyRecyclerCardviewAdapter(List<Integer> datas){
12         super();
13         this.mdatas = datas;
14     }
15
16
17     @Override
18     public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
19
20         if (viewType == ITEM_TYPE.ITEM_TYPE_Theme.ordinal()){
21
22             View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.videothemelist,parent,false);
23
24             return new ThemeVideoHolder(view);
25
26         }else if(viewType == ITEM_TYPE.ITEM_TYPE_Video.ordinal()){
27
28             View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.videocardview,parent,false);
29             return new VideoViewHolder(view);
30
31         }
32           return null;
33     }
34
35
36     @Override
37     public void onBindViewHolder(final ViewHolder holder, final int position) {
38
39         if (holder instanceof ThemeVideoHolder){
40
41            themeTitle.setText("励志");
42
43         }else if (holder instanceof VideoViewHolder){
44             ((VideoViewHolder)holder).videologo.setImageResource(R.drawable.lianzai_02);
45             ((VideoViewHolder)holder).videovname.setText("励志,俄小伙练习街头健身一年的体型变化,Dear Hard Work!");
46             ((VideoViewHolder)holder).videoviewed.setText("2780次");
47             ((VideoViewHolder)holder).videocomment.setText("209条");
48
49           }
50
51     }
52
53
54     public int getItemViewType(int position){
55
56         return position % 5 == 0 ? ITEM_TYPE.ITEM_TYPE_Theme.ordinal() : ITEM_TYPE.ITEM_TYPE_Video.ordinal();
57     }
58
59
60
61
62     @Override
63     public int getItemCount() {
64         return mdatas.size();
65     }
66
67
68     public class ThemeVideoHolder extends RecyclerView.ViewHolder{
69
70         public ThemeVideoHolder(View itemView) {
71             super(itemView);
72             themeTitle = (TextView) itemView.findViewById(R.id.hometab1_theme_title);
73         }
74     }
75
76     public class VideoViewHolder extends RecyclerView.ViewHolder {
77         public ImageView videologo;
78         public TextView videovname;
79         public TextView videoviewed;
80         public TextView videocomment;
81
82         public VideoViewHolder(View itemView) {
83             super(itemView);
84             videologo = (ImageView) itemView.findViewById(R.id.videologo);
85             videoviewed = (TextView) itemView.findViewById(R.id.videoviewed);
86             videocomment = (TextView) itemView.findViewById(R.id.videocomment);
87             videovname = (TextView) itemView.findViewById(R.id.videoname);
88         }
89     }
90 }  

这时,使用的是 LayoutManager 中发 LinearLayoutManager,效果图如下:

但是,当我们把 LayoutManager 改成GridLayoutManager的时候你就出现了不是我们期待的效果,如下图:

What the hell is going on? 什么鬼?怎么添加的header随着其他item项以cell的形式出现在网格上。仔细想一想,发现了下面代码

1 GridLayoutManager layoutManager = new GridLayoutManager(this,2, GridLayoutManager.VERTICAL,false);  

哦!原来我们在创建GridLayoutManager的时候需要设定每行显示多少个item项,我们这里设置的是2,而我们添加的header是以item项的形式添加进来的,所以也会以cell的形式出现。那么,有没有办法让header这个item占据两个cell,单独霸占一行呢?答案是肯定的,我们可以通过setSpanSizeLookup抽象类中的getSpanSize()方法的返回值来设定每个item项占据多少个单元格 。

1 gridManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
2             @Override
3             public int getSpanSize(int position) {
4                 return getItemViewType(position) == ITEM_TYPE.ITEM_TYPE_Theme.ordinal()
5                         ? gridManager.getSpanCount() : 1;
6             }
7         });  

那么,这段代码在自定义Adapter中应该添加在何处呢?放在onAttachedToRecyclerView()中再合适不过了。

 1 public void onAttachedToRecyclerView(RecyclerView recyclerView) {
 2         super.onAttachedToRecyclerView(recyclerView);
 3         RecyclerView.LayoutManager manager = recyclerView.getLayoutManager();
 4         if(manager instanceof GridLayoutManager) {
 5             final GridLayoutManager gridManager = ((GridLayoutManager) manager);
 6             gridManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
 7                 @Override
 8                 public int getSpanSize(int position) {
 9                     return getItemViewType(position) == ITEM_TYPE.ITEM_TYPE_Theme.ordinal()
10                             ? gridManager.getSpanCount() : 1;
11                 }
12             });
13         }
14     }  

这时就可以实现我想要的效果了,运行效果图如下:

代码我已经抽离出来放到我的Github了:RecycleViewWithHeader

2.最后说一下为什么为什么用RecyclerView取代ListView。

用过ListView的都知道,在ListView中若要复用视图缓存,就要在getView()方法中手动判断convertView是否为空,若不为空则复用视图缓存,若为空则重新加载视图,而RecyclerView相当于对ListView的Adapter进行了再次封装,把ListView手动判断是否有缓存的代码封装到RecyclerView内部,使这部分逻辑不可见,我们只需要通过getItemCount()方法告诉RecyclerView有多少项数据,然后在onCreateViewHolder()中加载item布局实例化ViewHolder,然后在onBindViewHolder()中完成数据的绑定即可。

时间: 2024-09-30 18:34:17

为RecyclerView的不同item项实现不同的布局(添加分类Header)的相关文章

RecyclerView高度随Item自适应 GridLayoutManager和LinearLayoutManager都适用

ScrollView嵌套RecyclerView时,android:layout_height="wrap_content"并不起作用,RecyclerView会填充剩余的整个屏幕空间,也就相当于android:layout_height="match_parent",通过重写GridLayoutManager或LinearLayoutManager 的onMeasure方法进行可重置RecyclerView的高度. 这里只给出GridLayoutManager的例

自定义ListView的点击Item项后进入另一个activity背景色改变在pressed或selected等状态时的颜色

在点击进入另一个activity时颜色改变是想在游戏攻略中实现的,但查资料找不到结果,今天突发灵感终于实现了. 我们大多数情况下都是自己写adapter,在写的那个Class中定义一个 boolean 型的 IsJump.然后在 OnItemClickListener 中 把 IsJump 设置为ture,再adapter2.notifyDataSetChanged();  在Adapter中 ture 的情况设置一种颜色就解决问题标记是否读过了.' 自定义ListView的Item项在pres

listView 解决焦点冲突问题 item项和子控件之间的冲突

listView 在item布局的顶级布局中设置 android:descendantFocusability="blocksDescendants"可以阻止子控件获取焦点 这样使item项可以点击 这时其中的图片控件还是可以点击的当不想让item能点击时 可以不加上边的设置 并且将焦点转移到子控件 focusable属性 <TextView android:id="@+id/recommend_album_more" android:layout_width

RecyclerView实现条目Item拖拽排序与滑动删除

RecyclerView实现条目Item拖拽排序与滑动删除 版权声明:转载请注明本文转自严振杰的博客: http://blog.csdn.net/yanzhenjie1003 效果演示 直播视频讲解:[http://pan.baidu.com/s/1miEOtwG1 推荐大家结合我直播的视频看效果更好. 本博客源码传送门. 需求和技术分析 RecyclerView Item拖拽排序::长按RecyclerView的Item或者触摸Item的某个按钮. RecyclerView Item滑动删除:

【Android 界面效果49】RecyclerView高度随Item自适应

编写RecyclerView.ItemDecoration时,在onDraw方法中,Drawable的高度等于RecyclerView的高度减去RecyclerView的上下padding. @Override public void onDraw(Canvas c, RecyclerView parent, State state) { int top = parent.getPaddingTop(); int bottom = parent.getHeight() - parent.getP

RecyclerView嵌套RecyclerView点击Item时顶上去的解决方法

RecyclerView嵌套RecyclerView点击Item时顶上去的原因是焦点抢占的原因,解决方法解决方法:holder.binding.rvContact.isFocusableInTouchMode = false (kotlin语法哦)注意:要在代码里面每次触发时设置,在xml里面一次性设置是无效的. 原文地址:https://www.cnblogs.com/yongfengnice/p/11445731.html

VS问题:该依赖项是由项目系统添加的,不能删除。

该依赖项是由项目系统添加的,不能删除. 原因:是该项目添加对依赖项的引用时,不是直接引用的dll,而是通过“添加引用->项目”的方式引用的项目. 解决:删除“引用”目录下该依赖项的引用,然后通过“添加引用->浏览”,添加对dll的引用,而不是对项目的引用.

删除ListView中所有Item项

今天做项目遇到一个一键删除ListView中所有列表项的需求,这里自己记录一下. 刚开始的想法是将设置一个空的Adapter,让后将空的Adapter赋给ListView,但后来想想这样太麻烦了,就去寻找了一下官方时候给了这样的方法. 别说,还真的有类似的方法! ViewGroup类下面有一个removeAllViews()方法,看名字就很像,试了一下竟然不行! 报了这样的错误: removeAllViews() is not supported in AdapterView 竟然说这个不是给A

Android Animation动画实战(一): 从布局动画引入ListView滑动时,每一Item项的显示动画

前言: 之前,我已经写了两篇博文,给大家介绍了Android的基础动画是如何实现的,如果还不清楚的,可以点击查看:Android Animation动画详解(一): 补间动画 及 Android Animation动画详解(二): 组合动画特效 . 已经熟悉了基础动画的实现后,便可以试着去实现常见APP中出现过的那些精美的动画.今天我主要给大家引入一个APP的ListView的动画效果: 当展示ListView时,Listview的每一个列表项都按照规定的动画显示出来. 说起来比较抽象,先给大家