RecyclerView使用指南(二)—— 多种ItemLayout

344 阅读3分钟

声明:原创作品,转载请注明出处:www.jianshu.com/p/7d30ba789…

我在上一篇文章《RecyclerView使用指南(一)—— 基本使用》中讲解了RecyclerView的最基本用法。 这一篇,我来讲解一下多种条目布局应该如何显示。(如果没看过上一篇文章的小朋友,建议去看一下短小的上一篇文章。。。) 没图说个**:

  • 核心思路:
  1. 针对不同的条目布局,我们创建不同的ViewHolder。
  2. Adapter需要知道在什么情况下使用什么样的布局。

Adapter中,我们可以通过重写getItemViewType(int position)方法,根据数据源,返回不同的viewType,Adapter在onCreateViewHolder和onBindViewHolder方法中使用这个值来创建ViewHolder和绑定相应的数据。

一、数据源为同种类型

总上所述,我们可以写一个简单的示例代码,它的数据源都是Data类型。如下:

package com.liuym.myapplication;

import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;

import java.util.List;

public class RvAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
    //条目类型
    public static final int TYPE_0 = 0;
    public static final int TYPE_1 = 1;

    //数据源
    private List<Data> mList;

    public RvAdapter(List<Data> list) {
        mList = list;
    }

    @NonNull
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int viewType) {
        View item;
        RecyclerView.ViewHolder holder = null;
        if (viewType == TYPE_0) {
            item = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.item_rv_type1, viewGroup, false);
            holder = new Type0ViewHolder(item);
        }
        if (viewType == TYPE_1) {
            item = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.item_rv_type2, viewGroup, false);
            holder = new Type1ViewHolder(item);
        }
        return holder;
    }

    /**
     * 根据数据源的某一项,返回相应的布局类别
     *
     * @param position
     * @return
     */
    @Override
    public int getItemViewType(int position) {
        return mList.get(position).getType();
    }

    @Override
    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int i) {
        int type = getItemViewType(i);
        Data data = mList.get(i);
        if (type == TYPE_0) {
            Type0ViewHolder holder = (Type0ViewHolder) viewHolder;
            holder.iv.setImageResource(R.drawable.ic_launcher_background);
            holder.tv.setText(data.getText());
        }
        if (type == TYPE_1) {
            Type1ViewHolder holder = (Type1ViewHolder) viewHolder;
            holder.iv.setImageResource(R.drawable.ic_launcher_background);
            holder.tv.setText(data.getText());
        }
    }

    @Override
    public int getItemCount() {
        return mList == null ? 0 : mList.size();
    }


    class Type0ViewHolder extends RecyclerView.ViewHolder {
        ImageView iv;
        TextView tv;

        public Type0ViewHolder(@NonNull View itemView) {
            super(itemView);
            iv = itemView.findViewById(R.id.iv);
            tv = itemView.findViewById(R.id.tv);
        }
    }

    class Type1ViewHolder extends RecyclerView.ViewHolder {
        ImageView iv;
        TextView tv;

        public Type1ViewHolder(@NonNull View itemView) {
            super(itemView);
            iv = itemView.findViewById(R.id.iv);
            tv = itemView.findViewById(R.id.tv);
        }
    }
}

二、数据源为不同类型

那么,如果我们要显示不同种类型的怎么办呢?比如这个列表既包含铅笔,又包含橡皮,怎么办? 这里,我们的数据源要包含两个类:Pencil类和Eraser类,为了将它们放到同一个列表中,我们可以让它们实现同一个接口,讲到这里,是不是有思路了呢? 好,我们来实现这个功能!

  1. 创建一个接口:
package com.liuym.myapplication;

public interface IMultiType {
    /**
     * 返回条目类型
     *
     * @return
     */
    int getItemType();
}
  1. 创建Pencil类实现IMultiType接口(Eraser类和Pencil类基本一致,只是返回的itemType不同):
package com.liuym.myapplication;

public class Pencil implements IMultiType {
    private String msg;

    public Pencil(String msg) {
        this.msg = msg;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    @Override
    public int getItemType() {
        return RvAdapter.TYPE_PENCIL;
    }
}
  1. 修改Adapter的数据源,将IMultiType的子类放入到数据源中,重写getItemViewType(int position)方法,完整代码如下:
package com.liuym.myapplication;

import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;

import java.util.List;

public class RvAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
    //条目类型
    public static final int TYPE_PENCIL = 0;
    public static final int TYPE_ERASER = 1;

    //数据源
    private List<IMultiType> mList;

    public RvAdapter(List<IMultiType> list) {
        mList = list;
    }

    @NonNull
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int viewType) {
        View item;
        RecyclerView.ViewHolder holder = null;
        if (viewType == TYPE_PENCIL) {
            item = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.item_rv_type1, viewGroup, false);
            holder = new PencilViewHolder(item);
        }
        if (viewType == TYPE_ERASER) {
            item = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.item_rv_type2, viewGroup, false);
            holder = new EraserViewHolder(item);
        }
        return holder;
    }

    /**
     * 根据数据源的某一项,返回相应的布局类别
     *
     * @param position
     * @return
     */
    @Override
    public int getItemViewType(int position) {
        return mList.get(position).getItemType();
    }

    @Override
    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int i) {
        int type = getItemViewType(i);
        if (type == TYPE_PENCIL) {
            Pencil pencil = (Pencil) mList.get(i);
            PencilViewHolder holder = (PencilViewHolder) viewHolder;
            holder.iv.setImageResource(R.drawable.ic_launcher_background);
            holder.tv.setText(pencil.getMsg());
        }
        if (type == TYPE_ERASER) {
            Eraser eraser = (Eraser) mList.get(i);
            EraserViewHolder holder = (EraserViewHolder) viewHolder;
            holder.iv.setImageResource(R.drawable.ic_launcher_background);
            holder.tv.setText(eraser.getMsg());
        }
    }

    @Override
    public int getItemCount() {
        return mList == null ? 0 : mList.size();
    }


    class PencilViewHolder extends RecyclerView.ViewHolder {
        ImageView iv;
        TextView tv;

        public PencilViewHolder(@NonNull View itemView) {
            super(itemView);
            iv = itemView.findViewById(R.id.iv);
            tv = itemView.findViewById(R.id.tv);
        }
    }

    class EraserViewHolder extends RecyclerView.ViewHolder {
        ImageView iv;
        TextView tv;

        public EraserViewHolder(@NonNull View itemView) {
            super(itemView);
            iv = itemView.findViewById(R.id.iv);
            tv = itemView.findViewById(R.id.tv);
        }
    }
}
  1. 设置数据源给Adapter,并将Adapter设置给RecyclerView
private void initRv() {
        List<IMultiType> list = new ArrayList<>();
        for (int i = 0; i < 20; i++) {
            if (i % 2 == 0) {
                String msg = String.format("eraser: %1s", i);
                list.add(new Eraser(msg));
            } else {
                String msg = String.format("pencil: %1s", i);
                list.add(new Pencil(msg));
            }
        }
        RecyclerView recyclerView = findViewById(R.id.rv);
        RvAdapter adapter = new RvAdapter(list);
        recyclerView.setAdapter(adapter);
    }

总结

这一篇,我讲解了如何在RecyclerView中使用不同的布局,下一篇,我会讲解如何给RecyclerView添加分割线以及给Item设置点击事件。

系列文章

《RecyclerView使用指南(一)—— 基本使用》
《RecyclerView使用指南(二)—— 多种ItemLayout》
《RecyclerView使用指南(三)—— 添加分割线和点击事件》
《RecyclerView使用指南(四)—— 使用ItemDecoration》
《RecyclerView使用指南(五)—— 实现吸顶效果》