RecyclerView-展示不同型別的物件
問題:
我們有三個不同型別的物件:Book ,Magazine和Newspaper.我們想只使用一個List就能展示它們,同時在RecyclerView中的展示也不一樣。
我們所需要的:
- 需要Book ,Magazine和Newspaper實現的一個介面。
- 一個RecyclerView.Adapter和一個可以強轉為不同型別的介面列表。
- 每種型別對應的ViewHolder和佈局檔案。
介面
首先,我們建立一個所有型別要實現的介面Literature.這個介面會有方法getType()和表示不同型別的常量。
public interface Literature { int TYPE_BOOK = 101; int TYPE_MAGAZINE = 102; int TYPE_NEWSPAPER = 103; int getType(); }
此時,每個型別都去實現介面Literature。重置getType()方法返回該物件的正確型別。
public class Book implements Literature { // variables and methods @Override public int getType() { return Literature.TYPE_BOOK; } } public class Magazine implements Literature{ // variables and methods @Override public int getType() { return Literature.TYPE_MAGAZINE; } } public class Newspaper implements Literature { // variables and methods @Override public int getType() { return Literature.TYPE_NEWSPAPER; } }
The RecyclerView.Adapter
首先,在Adapter裡新增我們的Literature介面作為成員變數。
public class LiteratureAdapter extends RecyclerView.Adapter { private List<Literature> mLiteratureList; }
我們同樣也需要三個ViewHolder作為Adapter的內部類。一個物件一個內部類。
public class LiteratureAdapter extends RecyclerView.Adapter { ... class BookViewHolder extends RecyclerView.ViewHolder { public BookViewHolder(View itemView) { super(itemView); // get reference to views // itemView.findViewById... } void bindView(int position) { Book book = (Book) mLiteratureList.get(position); // bind data to the views // textView.setText()... } } class MagazineViewHolder extends RecyclerView.ViewHolder { public MagazineViewHolder(View itemView) { super(itemView); // get reference to views } void bindView(int position) { Magazine magazine = (Magazine) mLiteratureList.get(position); // bind data to the views } } class NewspaperViewHolder extends RecyclerView.ViewHolder { public NewspaperViewHolder(View itemView) { super(itemView); // get reference to views } void bindView(int position) { Newspaper newspaper = (Newspaper) mLiteratureList.get(position); // bind data to the views } } }
我們需要重寫RecyclerView.Adapter的四個方法。第一個就是getItemViewType()。此方法將會取出mLiteratureList裡的一個條目,判斷是否為一個Book, Magazine,或者Newspaper,然後將結果傳給onCreateViewHolder()(此方法將會在後面實現)
@Override public int getItemViewType(int position) { return mLiteratureList.get(position).getType(); }
在onCreateViewHolder()中,我們會根據getItemViewType()傳過來的型別建立一個ViewHolder
@NonNull @Override public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View itemView; switch (viewType) { case Literature.TYPE_BOOK: itemView = LayoutInflater.from(parent.getContext()) .inflate(R.layout.your_layout, parent, false); return new BookViewHolder(itemView); case Literature.TYPE_MAGAZINE: itemView = LayoutInflater.from(parent.getContext()) .inflate(R.layout.your_layout, parent, false); return new MagazineViewHolder(itemView); default: // TYPE_NEWSPAPER itemView = LayoutInflater.from(parent.getContext()) .inflate(R.layout.your_layout, parent, false); return new NewspaperViewHolder(itemView); } }
在onBindViewHolder()中呼叫getItemViewType()。取決於返回的型別,將通用的ViewHolder強轉為合適的型別,然後呼叫起bindView()方法。
@Override public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { switch (getItemViewType(position)) { case Literature.TYPE_BOOK: ((BookViewHolder) holder).bindView(position); break; case Literature.TYPE_MAGAZINE: ((MagazineViewHolder) holder).bindView(position); break; case Literature.TYPE_NEWSPAPER: ((NewspaperViewHolder) holder).bindView(position); break; } }
getItemCount()裡的方法和以前標準的RecyclerView.Adapter的程式碼是一樣的。
@Override public int getItemCount() { if (mLiteratureList == null) { return 0; } else { return mLiteratureList.size(); } }
設定資料
public void setLiteratureList(List<? extends Literature> literatureList) { if (mLiteratureList == null){ mLiteratureList = new ArrayList<>(); } mLiteratureList.clear(); mLiteratureList.addAll(literatureList); notifyDataSetChanged(); }
好啦,點到為止。好好享受你的RecyclerView.Adapter吧。
翻譯自:ofollow,noindex">Display Objects of Different Types in a RecyclerView