使用一个 RecyclerView 构建复杂多类型布局

在学习 RecyclerView 过程中,发现它不只是用来展示简单列表,还支持在同一个列表中灵活混排不同布局的内容。这个功能是通过 getItemViewType 实现的,本文通过一个具体的例子记录了如何使用它来实现多种类型的列表项展示。

需求

实现一个页面,支持以下三种类型的列表项:

  1. 标题项(ViewType 0):仅显示一段文字标题。
  2. 内容项(ViewType 1):一行三列文字展示。
  3. 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
  • 绑定对应的数据与逻辑

这种方式在构建如新闻流、商城首页、混合表单等复杂界面中非常实用。

相关推荐
郑州光合科技余经理27 分钟前
国际版外卖系统:税率字段怎么和订单主流程解耦
android·java·开发语言·前端·后端·php·ai编程
andyweike5 小时前
Android Automotive
android
又见情义6 小时前
记一次 RK3568 Android 13 蓝牙反复重启问题的排查与修复
android
hai_android6 小时前
Kotlin Flow combine 源码剖析:一个 Channel 如何优雅合并多条流
android·java·kotlin
敲代码的瓦龙7 小时前
Jetpack?ViewModel!!!
android·开发语言·kotlin·android-studio
Godikov8 小时前
Android 工控终端实战:从秒级卡顿到毫秒响应,SQLite/LitePal 性能优化全记录
android
星间都市山脉10 小时前
Android16 SystemService.onBootPhase 调用时机
android·java·linux·windows·ubuntu
swithun10 小时前
不用 WebView,我用 Kotlin + Compose Multiplatform 重写 Mermaid,并做了 2048 组对拍
android·开源·kotlin
AI吃大瓜10 小时前
人脸检测和行人检测4:Android实现YOLOv8 YOLO11 YOLO26人脸检测和人体检测(含源码,可实时检测)
android·yolo·人脸检测·人体检测·行人检测·yolo26
与海boy10 小时前
Prompt模版
android·prompt