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

will20151115發表於2018-11-27

宣告:原創作品,轉載請註明出處:www.jianshu.com/p/7d30ba789…

我在上一篇文章《RecyclerView使用指南(一)—— 基本使用》中講解了RecyclerView的最基本用法。 這一篇,我來講解一下多種條目佈局應該如何顯示。(如果沒看過上一篇文章的小朋友,建議去看一下短小的上一篇文章。。。) 沒圖說個**:

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

  • 核心思路:
  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使用指南(五)—— 實現吸頂效果》

相關文章