RecyclerView替代ListView 出道已经好几年了,作为开发者应该也都比较熟悉了,以及它的各种优势和方便多样化列表布局就更不用说了。
RecyclerView标准化了ViewHolder,可以轻松实现ListView实现不了的样式和功能,通过布局管理器LayoutManager可控制Item的布局方式,通过设置Item操作动画自定义Item添加和删除的动画,通过设置Item之间的间隔样式,自定义间隔。
总感觉RecyclerView已经是万能的了,对于复杂的列表界面和各种不同样式的Item都可以搞定,甚至我感觉好多资讯或者非资讯类的app一个页面只用一个RecyclerView都能做到,比如资讯类APP详情页头部是新闻详情中间又是相关新闻列表底部又是评论,评论上滑动加载更多,和大部分APP主要界面的各种不一样的列表,这些应该都是一个RecyclerView搞定的吧。
但是官网对RecyclerView也有它自己的解释:
The RecyclerView widget is a more advanced and flexible version of ListView. This widget is a container for displaying large data sets that can be scrolled very efficiently by maintaining a limited number of views. Use the RecyclerView widget when you have data collections whose elements change at runtime based on user action or network events.
这段解释意境很清楚,我们确实可以把它看作一个[advanced]的ListView,但是这里我想说的是,千万不要把RecyclerView看成能和ListView[等价替换]的一个组件,更不要把它看做是拯救你滑动组件的救星。
但是不管怎么样现在自己开发基本的列表页面都是一个RecyclerView控件来做的,基本也就是自己去写添加头部和添加尾部和中间插入自己想要布局的GroupLayout 都可以满足各种需求UI样式。
记录下自己参照网上一些大神例子写了个Demo。、
这就是效果,一个RecyclerView完成的,甚至还可以做更复杂的布局,不同的样式。
也不是特别的难主要就是添加头部尾部中间插入放Adapter getItemViewType不同的类型进行区分
主要注意一点,可以能添加了头,尾部之后就得重新去获取真实的position 要不然就会报数组越界错误。
这个是我的adapter 是根据真实的position 来显示不同样式的item,
if (listBeans.get(getPosition(position)).getReplies_count() ==1) {
return TYPE_1;
}else if (listBeans.get(getPosition(position)).getReplies_count() ==2) {
return TYPE_2;
}else if (listBeans.get(getPosition(position)).getReplies_count() ==3) {
return TYPE_3;
}else if (listBeans.get(getPosition(position)).getReplies_count() ==4) {
return TYPE_4;
}else if (listBeans.get(getPosition(position)).getReplies_count() ==5) {
return TYPE_5;
}else if (listBeans.get(getPosition(position)).getReplies_count() ==6) {
return TYPE_6;
}else {
return TYPE_7;
}
}
这是整个Adapter类,我只是便于代码的分类把ViewHolder和onBindViewHolder绑定数据的分别都写到外面去了而已,如果这三个类 读写在Adapter里面的话到时候这个类会很臃肿代码量很大,分别写到外面去的话应该都知道是为了后期维护,以及代码的整洁,明确易于查找。
1、Adapter类
package com.example.recycleview_multi_layout.adapter;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.recyclerview.widget.RecyclerView;
import com.example.recycleview_multi_layout.Model;
import com.example.recycleview_multi_layout.R;
import java.util.List;
public class Adapter extends RecyclerView.Adapter {
private static final int HEADER_VIEW =0;
private static final int NORMAL_VIEW =1;
private static final int TYPE_MIDDLE =2;
private static final int TYPE_MIDDLE_TWO =3;
private static final int TYPE_1 =4;
private static final int TYPE_2 =5;
private static final int TYPE_3 =6;
private static final int TYPE_4 =7;
private static final int TYPE_5 =8;
private static final int TYPE_6 =9;
private static final int TYPE_7 =10;
private View mHeaderView;
private View mMiddleView;
private View mMiddleView2;
private ListlistBeans;
private OnClickListener mItemClickListener;
BaseBindViewHolder baseBindViewHolder=new BaseBindViewHolder();
private Context mContext;
public void setItemClickListener(OnClickListener itemClickListener) {
mItemClickListener = itemClickListener;
}
public void setHeaderView(View headerView) {
mHeaderView = headerView;
}
public void setMiddleView(View middleView) {
mMiddleView = middleView;
}
public void setMiddleView2(View middleView2) {
mMiddleView2 = middleView2;
}
public Adapter(List list, Context context) {
this.listBeans = list;
this.mContext = context;
}
@Override
public int getItemCount() {
if (listBeans !=null &&listBeans.size() !=0) {
return listBeans.size() +3;
}
return 0;
}
@Override
public int getItemViewType(int position) {
if (position ==0) {
return HEADER_VIEW;
}
if (position ==5) {
return TYPE_MIDDLE;
}
if (position ==10) {
return TYPE_MIDDLE_TWO;
}else {
if (listBeans.get(getPosition(position)).getReplies_count() ==1) {
return TYPE_1;
}else if (listBeans.get(getPosition(position)).getReplies_count() ==2) {
return TYPE_2;
}else if (listBeans.get(getPosition(position)).getReplies_count() ==3) {
return TYPE_3;
}else if (listBeans.get(getPosition(position)).getReplies_count() ==4) {
return TYPE_4;
}else if (listBeans.get(getPosition(position)).getReplies_count() ==5) {
return TYPE_5;
}else if (listBeans.get(getPosition(position)).getReplies_count() ==6) {
return TYPE_6;
}else {
return TYPE_7;
}
}
}
public int getPosition(int i) {
if (i <4) {
return i -1;
}
if (i >4 && i <10) {
return i -2;
}else {
return i -3;
}
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (mHeaderView !=null && viewType ==HEADER_VIEW) {
return new BaseViewHolder(mHeaderView);
}
if (mMiddleView !=null && viewType ==TYPE_MIDDLE) {
return new BaseViewHolder(mMiddleView);
}
if (mMiddleView2 !=null && viewType ==TYPE_MIDDLE_TWO) {
return new BaseViewHolder(mMiddleView2);
}
if (viewType ==TYPE_1) {
return new BaseViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_type1, null, false));
}else if (viewType ==TYPE_2) {
return new BaseViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_type2, null, false));
}else if (viewType ==TYPE_3) {
return new BaseViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_type3, null, false));
}else if (viewType ==TYPE_4) {
return new BaseViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_type4, null, false));
}else if (viewType ==TYPE_5) {
return new BaseViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_type5, null, false));
}else if (viewType ==TYPE_6) {
return new BaseViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_type6, null, false));
}else {
return new BaseViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_type0, null, false));
}
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
if (getItemViewType(position) ==HEADER_VIEW) {
if (holderinstanceof BaseViewHolder) {
baseBindViewHolder.onBindViewHolder0(holder,listBeans);
}
return;
}
if (getItemViewType(position) ==TYPE_MIDDLE) {
if (holderinstanceof BaseViewHolder) {
}
return;
}
if (getItemViewType(position) ==TYPE_MIDDLE_TWO) {
if (holderinstanceof BaseViewHolder) {
baseBindViewHolder.onBindTYPE_MIDDLE_TWO(holder,listBeans,mContext);
}
return;
}
if (getItemViewType(position) ==TYPE_1) {
if (holderinstanceof BaseViewHolder) {
baseBindViewHolder.onBindViewHolder1(holder,listBeans);
}
return;
}
if (getItemViewType(position) ==TYPE_2) {
if (holderinstanceof BaseViewHolder) {
baseBindViewHolder.onBindViewHolder2(holder,listBeans);
}
return;
}
if (getItemViewType(position) ==TYPE_3) {
if (holderinstanceof BaseViewHolder) {
baseBindViewHolder.onBindViewHolder3(holder,listBeans);
}
return;
}
if (getItemViewType(position) ==TYPE_4) {
if (holderinstanceof BaseViewHolder) {
baseBindViewHolder.onBindViewHolder4(holder,listBeans);
}
return;
}
if (getItemViewType(position) ==TYPE_5) {
if (holderinstanceof BaseViewHolder) {
baseBindViewHolder.onBindViewHolder5(holder,listBeans);
}
return;
}
if (getItemViewType(position) ==TYPE_6) {
if (holderinstanceof BaseViewHolder) {
baseBindViewHolder.onBindViewHolder6(holder,listBeans);
}
return;
}
final int pos =getRealPosition(holder);
if (getItemViewType(position) ==TYPE_7) {
if (holderinstanceof BaseViewHolder) {
baseBindViewHolder.onBindViewHolder7(holder,listBeans);
if (mItemClickListener ==null) {
return;
}
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mItemClickListener.onItemClick(v, pos);
}
});
}
return;
}
}
// 获取条目的真实位置
public int getRealPosition(RecyclerView.ViewHolder holder) {
int position = holder.getLayoutPosition();
if (position <5) {
return position -1;
}
if (position >5 &&position <10) {
return position -2;
}else {
return position -3;
}
}
interface OnClickListener {
void onItemClick(View view, int position);
}
}
2、 RecyclerView.ViewHolder 视图类
public class BaseViewHolder extends RecyclerView.ViewHolder {
public ImageView headlineImg, headlineImg2, headlineImg3;
public TextView title,sourceTitle, sourceSummary,summary;
public RoundedImageView sourceImage;
public Banner banner;
public RecyclerView recyclerView;
public BaseViewHolder(@NonNull View itemView) {
super(itemView);
headlineImg = itemView.findViewById(R.id.headline_img);
headlineImg2 = itemView.findViewById(R.id.headline_img2);
headlineImg3 = itemView.findViewById(R.id.headline_img3);
sourceImage = itemView.findViewById(R.id.source_image);
title = itemView.findViewById(R.id.title);
sourceTitle = itemView.findViewById(R.id.source_title);
sourceSummary = itemView.findViewById(R.id.source_summary);
summary = itemView.findViewById(R.id.summary);
banner = itemView.findViewById(R.id.banner);
recyclerView= itemView.findViewById(R.id.recyclerView);
}
}
3、BindViewHolder 绑定数据类
public class BaseBindViewHolder {
public void onBindViewHolder0(RecyclerView.ViewHolder holder, List listBeans) {
List list = new ArrayList<>();
list.add(R.mipmap.response01);
list.add(R.mipmap.response02);
list.add(R.mipmap.response03);
list.add(R.mipmap.response04);
list.add(R.mipmap.response05);
list.add(R.mipmap.response06);
((BaseViewHolder) holder).banner.setImages(list)
.setImageLoader(new GlideImageLoader())
.start();
}
private List fruitList = new ArrayList<>();
public void onBindTYPE_MIDDLE_TWO(RecyclerView.ViewHolder holder, List listBeans, Context context) {
initFruits();
LinearLayoutManager layoutManager = new LinearLayoutManager(context);
layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
((BaseViewHolder) holder).recyclerView.setLayoutManager(layoutManager);
RecyclerAdapter adapter = new RecyclerAdapter(fruitList);
((BaseViewHolder) holder).recyclerView.setAdapter(adapter);
}
private void initFruits() {
for (int i = 0; i < 2; i++) {
Fruit apple = new Fruit("HHH", R.mipmap.response01);
fruitList.add(apple);
Fruit banana = new Fruit("AAA", R.mipmap.response02);
}
}
public void onBindViewHolder1(RecyclerView.ViewHolder holder, List listBeans) {
final int pos = getRealPosition(holder);
((BaseViewHolder) holder).title.setText(listBeans.get(pos).getTitle());
if (!TextUtils.isEmpty(listBeans.get(pos).getHeadline_img())) {
XImageOptions.imageData(((BaseViewHolder) holder).headlineImg, listBeans.get(pos).getHeadline_img());
} else {
XImageOptions.imageData(((BaseViewHolder) holder).headlineImg, "http://liveimg.miaobolive.com/pic/avator/201910/26/15/E31ED19F926F874063215984_640.png");
}
}
public void onBindViewHolder2(RecyclerView.ViewHolder holder, List listBeans) {
final int pos = getRealPosition(holder);
((BaseViewHolder) holder).title.setText(listBeans.get(pos).getTitle());
XImageOptions.imageData(((BaseViewHolder) holder).headlineImg, listBeans.get(pos).getHeadline_img());
XImageOptions.imageData(((BaseViewHolder) holder).headlineImg2, listBeans.get(pos).getHeadline_img());
XImageOptions.imageData(((BaseViewHolder) holder).headlineImg3, listBeans.get(pos).getHeadline_img());
}
public void onBindViewHolder3(RecyclerView.ViewHolder holder, List listBeans) {
final int pos = getRealPosition(holder);
((BaseViewHolder) holder).title.setText(listBeans.get(pos).getTitle());
((BaseViewHolder) holder).summary.setText(listBeans.get(pos).getSummary());
XImageOptions.imageData(((BaseViewHolder) holder).headlineImg, listBeans.get(pos).getHeadline_img());
}
public void onBindViewHolder4(RecyclerView.ViewHolder holder, List listBeans) {
final int pos = getRealPosition(holder);
((BaseViewHolder) holder).title.setText(listBeans.get(pos).getTitle());
XImageOptions.imageData(((BaseViewHolder) holder).headlineImg, listBeans.get(pos).getHeadline_img());
XImageOptions.imageData(((BaseViewHolder) holder).headlineImg2, listBeans.get(pos).getHeadline_img());
XImageOptions.imageData(((BaseViewHolder) holder).headlineImg3, listBeans.get(pos).getHeadline_img());
}
public void onBindViewHolder5(RecyclerView.ViewHolder holder, List listBeans) {
final int pos = getRealPosition(holder);
((BaseViewHolder) holder).title.setText(listBeans.get(pos).getTitle());
XImageOptions.imageData(((BaseViewHolder) holder).headlineImg, listBeans.get(pos).getHeadline_img());
XImageOptions.imageData(((BaseViewHolder) holder).headlineImg2, listBeans.get(pos).getHeadline_img());
XImageOptions.imageData(((BaseViewHolder) holder).headlineImg3, listBeans.get(pos).getHeadline_img());
}
public void onBindViewHolder6(RecyclerView.ViewHolder holder, List listBeans) {
final int pos = getRealPosition(holder);
((BaseViewHolder) holder).title.setText(listBeans.get(pos).getTitle());
((BaseViewHolder) holder).sourceTitle.setText(listBeans.get(pos).getSource_data().getTitle());
((BaseViewHolder) holder).sourceSummary.setText(listBeans.get(pos).getSource_data().getSummary());
XImageOptions.imageData(((BaseViewHolder) holder).headlineImg, listBeans.get(pos).getHeadline_img());
XImageOptions.imageData(((BaseViewHolder) holder).sourceImage, listBeans.get(pos).getSource_data().getImage());
}
public void onBindViewHolder7(RecyclerView.ViewHolder holder, List listBeans) {
final int pos = getRealPosition(holder);
((BaseViewHolder) holder).title.setText(listBeans.get(pos).getTitle());
if (TextUtils.isEmpty(listBeans.get(pos).getHeadline_img())||listBeans.get(pos).getHeadline_img()==null) {
XImageOptions.imageData(((BaseViewHolder) holder).headlineImg, "http://2-im.guokr.com/BL-zs0S2cMtowORGmuKri_mYXjze4UY0ZkX-WGWn5Ug4BAAAvAEAAEpQ.jpg?imageView2/1/w/1080/h/444");
} else {
XImageOptions.imageData(((BaseViewHolder) holder).headlineImg, listBeans.get(pos).getHeadline_img());
}
}
// 获取条目的真实位置
public int getRealPosition(RecyclerView.ViewHolder holder) {
int position = holder.getLayoutPosition();
if (position < 5) {
return position - 1;
}
if (position > 5 && position < 10) {
return position - 2;
} else {
return position - 3;
}
}
public class GlideImageLoader extends ImageLoader {
@Override
public void displayImage(Context context, Object path, ImageView imageView) {
Glide.with(context.getApplicationContext())
.load(path)
.into(imageView);
}
}
}
里面的变量命名我就随便的有些是直接复制的就没改了。
最后Demo 已经上传GitHub: https://github.com/MirShu/RecycleView_Multi_Layout