在学习 RecyclerView
过程中,发现它不只是用来展示简单列表,还支持在同一个列表中灵活混排不同布局的内容。这个功能是通过 getItemViewType
实现的,本文通过一个具体的例子记录了如何使用它来实现多种类型的列表项展示。
需求
实现一个页面,支持以下三种类型的列表项:
- 标题项(ViewType 0):仅显示一段文字标题。
- 内容项(ViewType 1):一行三列文字展示。
- Banner项(ViewType 2):一整行图片 Banner。
效果图

实现代码
数据结构定义
js
public abstract class BaseItem {
public static final int TYPE_TITLE = 0;
public static final int TYPE_CONTENT = 1;
public static final int TYPE_BANNER = 2;
public abstract int getType();
}
public class TitleItem extends BaseItem {
public String title;
public TitleItem(String title) {
this.title = title;
}
@Override
public int getType() {
return TYPE_TITLE;
}
}
public class ContentItem extends BaseItem {
public String content;
public ContentItem(String content) {
this.content = content;
}
@Override
public int getType() {
return TYPE_CONTENT;
}
}
public class BannerItem extends BaseItem {
public int imageResId;
public BannerItem(int imageResId) {
this.imageResId = imageResId;
}
@Override
public int getType() {
return TYPE_BANNER;
}
}
自定义 RecyclerView Adapter
js
public class MultiTypeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private List<BaseItem> items;
public MultiTypeAdapter(List<BaseItem> items) {
this.items = items;
}
@Override
public int getItemViewType(int position) {
return items.get(position).getType();
}
@Override
public int getItemCount() {
return items.size();
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
if (viewType == BaseItem.TYPE_TITLE) {
View view = inflater.inflate(R.layout.item_title, parent, false);
return new TitleViewHolder(view);
} else if (viewType == BaseItem.TYPE_CONTENT) {
View view = inflater.inflate(R.layout.item_content, parent, false);
return new ContentViewHolder(view);
} else {
View view = inflater.inflate(R.layout.item_banner, parent, false);
return new BannerViewHolder(view);
}
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
BaseItem item = items.get(position);
if (holder instanceof TitleViewHolder) {
((TitleViewHolder) holder).bind((TitleItem) item);
} else if (holder instanceof ContentViewHolder) {
((ContentViewHolder) holder).bind((ContentItem) item);
} else if (holder instanceof BannerViewHolder) {
((BannerViewHolder) holder).bind((BannerItem) item);
}
}
static class TitleViewHolder extends RecyclerView.ViewHolder {
TextView titleText;
TitleViewHolder(View view) {
super(view);
titleText = view.findViewById(R.id.title_text);
}
void bind(TitleItem item) {
titleText.setText(item.title);
}
}
static class ContentViewHolder extends RecyclerView.ViewHolder {
TextView contentText;
ContentViewHolder(View view) {
super(view);
contentText = view.findViewById(R.id.content_text);
}
void bind(ContentItem item) {
contentText.setText(item.content);
}
}
static class BannerViewHolder extends RecyclerView.ViewHolder {
ImageView image;
BannerViewHolder(View view) {
super(view);
image = view.findViewById(R.id.banner_image);
}
void bind(BannerItem item) {
image.setImageResource(item.imageResId);
}
}
}
初始化与使用
js
List<BaseItem> itemList = new ArrayList<>();
itemList.add(new TitleItem("今日推荐"));
itemList.add(new ContentItem("苹果"));
itemList.add(new ContentItem("香蕉"));
itemList.add(new ContentItem("普通"));
itemList.add(new BannerItem(R.drawable.image_banner));
itemList.add(new TitleItem("本周热点"));
itemList.add(new ContentItem("科技"));
itemList.add(new ContentItem("财经"));
itemList.add(new ContentItem("体育"));
RecyclerView.Adapter<RecyclerView.ViewHolder> adapter = new MultiTypeAdapter(itemList);
GridLayoutManager layoutManager = new GridLayoutManager(context, 3);
layoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
@Override
public int getSpanSize(int position) {
int viewType = adapter.getItemViewType(position);
if (viewType == BaseItem.TYPE_CONTENT) {
return 1; // 占1列
} else {
return 3; // 标题和 Banner 占整行
}
}
});
recyclerView.setLayoutManager(layoutManager);
recyclerView.setAdapter(adapter);
总结
通过合理使用 RecyclerView 的 ViewType 能力,我们可以在一个列表中自由混排多种样式的布局元素。关键点在于:
- 定义数据类型与 ViewType 映射
- 根据类型加载不同的布局文件与 ViewHolder
- 绑定对应的数据与逻辑
这种方式在构建如新闻流、商城首页、混合表单等复杂界面中非常实用。