本來這一個主題應該早就寫了,只是項目多,屬於自己的時間不多,所以現在才開動!!
前一段時間寫了一篇文章,是關於ListView,GriView萬能適配器,沒有看過的同學,可以先看看那篇文章,然后在來學習RecyclerView的話,會容易很多。鏈接http://www.cnblogs.com/huangjialin/p/7661328.html
當然,如果對RecyclerView基礎不是了解的朋友,建議先去熟悉一下RecyclerView的基礎知識!
閑話不多說,先簡單的介紹一下這個RecyclerView,它是Android5.0的時候出來的一個新控件,主要目的就是替代ListView和GridView,也就是說RecyclerView能夠實現ListView和GridView的效果,甚至比原來的更好,更方便,
我們知道,在寫ListView和GridView的時候,都需要寫一個適配器,然后繼承BaseAdapter,接着實現幾個方法,套路都是一樣的,但是前一段時間寫了一個通用的適配器,所以在寫ListView和GridView的adapter的時候,可以省了很多事,方便了許多,那么,問題來了,
RecyclerView的通用適配器怎么寫呢???
我們知道,在寫ListView和GridView的適配器時候,我們需要考慮view的復用機制,但是RecyclerView內部已經幫我們寫好了復用機制,所以,我們不需要考慮復用的情況,先不說,從ViewHolder開始
通用ViewHoler
1 package com.xiaoma.xting.adapter; 2 3 import android.content.Context; 4 import android.support.v7.widget.RecyclerView; 5 import android.util.SparseArray; 6 import android.view.LayoutInflater; 7 import android.view.View; 8 import android.view.ViewGroup; 9 import android.widget.ImageView; 10 import android.widget.TextView; 11 12 /** 13 * Created by Administrator on 2017/11/6 0006. 14 * huangjialin 15 */ 16 17 public class BaseViewHolder extends RecyclerView.ViewHolder { 18 private SparseArray<View> mViews; //用來存儲控件 19 private View mConvertView; 20 private Context mContext; 21 22 23 public BaseViewHolder(Context context, View itemView) { 24 super(itemView); 25 this.mContext = context; 26 mConvertView = itemView; 27 mViews = new SparseArray<View>(); 28 } 29 30 31 /** 32 * 提供一個獲取ViewHolder的方法 33 */ 34 public static BaseViewHolder getRecyclerHolder(Context context, ViewGroup parent, int layoutId) { 35 View itemView = LayoutInflater.from(context).inflate(layoutId, parent, false); 36 BaseViewHolder viewHolder = new BaseViewHolder(context, itemView); 37 return viewHolder; 38 } 39 40 41 /** 42 * 獲取控件 43 */ 44 public <T extends View> T getView(int viewId) { 45 View view = mViews.get(viewId); 46 if (view == null) { 47 view = mConvertView.findViewById(viewId); 48 mViews.put(viewId, view); 49 } 50 return (T) view; 51 } 52 53 54 /** 55 * 給TextView設置setText方法 56 */ 57 public BaseViewHolder setText(int viewId, String text) { 58 TextView tv = getView(viewId); 59 tv.setText(text); 60 return this; 61 } 62 63 64 /** 65 * 給ImageView設置setImageResource方法 66 */ 67 public BaseViewHolder setImageResource(int viewId, int resId) { 68 ImageView view = getView(viewId); 69 view.setImageResource(resId); 70 return this; 71 } 72 73 /** 74 * 添加點擊事件 75 */ 76 public BaseViewHolder setOnClickListener(int viewId, View.OnClickListener listener) { 77 View view = getView(viewId); 78 view.setOnClickListener(listener); 79 return this; 80 } 81 }
代碼中,創建了BaseViewHolder,並且繼承RecyclerView的ViewHoler,我們對外提供兩個方法,一個是獲取viewholder的getRecyclerHolder()方法,另一個是獲取控件的getView()方法,由於RecyclerView的保存控件的方式是以變量的形式來,而這里則是通過SparseArray來通過key來進行存儲的。
通用適配器
前面viewholer,現在看看adapter,先上代碼
1 package com.example.administrator.recylerviewadaptertest; 2 3 import android.content.Context; 4 import android.support.v7.widget.RecyclerView; 5 import android.view.ViewGroup; 6 7 import java.util.List; 8 9 /** 10 * Created by Administrator on 2017/11/6 0006. 11 * huangjialin 12 * 普通類型的適配器 13 */ 14 15 public abstract class BaseRecyclerAdapter<T> extends RecyclerView.Adapter<BaseViewHolder> { 16 private Context mContext; 17 private int mLayoutId; 18 private List<T> mData; 19 20 21 public BaseRecyclerAdapter(Context mContext, int mLayoutId, List<T> mData) { 22 this.mContext = mContext; 23 this.mLayoutId = mLayoutId; 24 this.mData = mData; 25 } 26 27 @Override 28 public BaseViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 29 BaseViewHolder viewHolder = BaseViewHolder.getRecyclerHolder(mContext, parent, mLayoutId); 30 return viewHolder; 31 } 32 33 @Override 34 public void onBindViewHolder(BaseViewHolder holder, int position) { 35 convert(holder, mData.get(position)); 36 37 } 38 39 @Override 40 public int getItemCount() { 41 return mData.size(); 42 } 43 44 /** 45 * 對外提供的方法 46 */ 47 public abstract void convert(BaseViewHolder holder, T t); 48 49 }
代碼不多,也相對簡單,在onCreateViewHolder()方法中,獲取到viewholer,然后我們自己定義一個convert()方法,對外提供該方法。那么,我們怎么用呢?
1 package com.example.administrator.recylerviewadaptertest; 2 3 import android.app.Activity; 4 import android.support.v7.app.AppCompatActivity; 5 import android.os.Bundle; 6 import android.support.v7.widget.LinearLayoutManager; 7 import android.support.v7.widget.RecyclerView; 8 import android.widget.TextView; 9 10 import java.util.ArrayList; 11 import java.util.List; 12 13 public class MainActivity extends Activity { 14 private RecyclerView recycler; 15 private BaseRecyclerAdapter mAdapter; 16 private List<String> stringList = new ArrayList<String>(); 17 18 @Override 19 protected void onCreate(Bundle savedInstanceState) { 20 super.onCreate(savedInstanceState); 21 setContentView(R.layout.activity_main); 22 23 recycler = findViewById(R.id.recycler); 24 25 mAdapter = new BaseRecyclerAdapter<String>(this, R.layout.rl_item_view, stringList) { 26 @Override 27 public void convert(BaseViewHolder holder, String s) { 28 holder.setText(R.id.test, s); 29 } 30 }; 31 32 LinearLayoutManager manager = new LinearLayoutManager(this); 33 recycler.setLayoutManager(manager); 34 recycler.setAdapter(mAdapter); 35 36 37 for (int i = 0; i < 50; i++) { 38 stringList.add("測試-->" + i); 39 } 40 mAdapter.notifyDataSetChanged(); 41 42 43 } 44 }
這些都相對來說很簡單如果有朋友覺得看不懂的話,我強烈建議先去看一下前面寫的ListView通用適配器,然后回來你就會發現很簡單了,套路都是差不多。
ItemViewType
前面寫的相對來說是針對與一些常見的列表布局,如果說復雜一些的布局,可能就行不通了,比如說我一個列表第一個item垂直顯示若干個控件,第二個item我水平顯示若干個控件,按照以往的經驗,我們通常會
在adapter中實現getItemViewType()方法,然后進行一些判斷,但是通用適配器中改怎么實現呢??
從前面獲取viewholder的時候,我們知道viewholder是通過布局來id來進行獲取的,那么,我們能不能這樣寫呢,我們通過不同的布局,來獲取不同的viewholder呢
我們在BaseRecyclerAdapter中加上這個接口
1 /** 2 * 針對多種類型的itemView 3 * @param <T> 4 */ 5 public interface ConmonItemType<T> { 6 int getLayoutId(int itemType); //不同的Item的布局 7 8 int getItemViewType(int position, T t); //type 9 }
然后我們新創建一個adapter並且繼承BaseRecyclerAdapter,代碼:
1 package com.example.administrator.recylerviewadaptertest; 2 3 import android.content.Context; 4 import android.view.ViewGroup; 5 6 import java.util.List; 7 8 /** 9 * Created by Administrator on 2017/11/6 0006. 10 * huangjialin 11 * 如果列表的布局item有多種類型,則需要繼承該適配器 12 */ 13 14 public abstract class MultiItemCommonAdapter<T> extends BaseRecyclerAdapter<T> { 15 private ConmonItemType<T> mConmonItemType; 16 private List<T> mDatas; 17 private Context mContext; 18 19 20 public MultiItemCommonAdapter(Context mContext, List<T> mData, ConmonItemType<T> conmonItemType) { 21 super(mContext, -1, mData); 22 this.mConmonItemType = conmonItemType; 23 mDatas = mData; 24 this.mContext = mContext; 25 } 26 27 @Override 28 public int getItemViewType(int position) { 29 return mConmonItemType.getItemViewType(position, mDatas.get(position)); 30 } 31 32 33 @Override 34 public BaseViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 35 int layoutId = mConmonItemType.getLayoutId(viewType); 36 BaseViewHolder holder = BaseViewHolder.getRecyclerHolder(mContext, parent, layoutId); 37 return holder; 38 } 39 }
從代碼可以看出,我們通過構造方法從外面傳進來的ConmonItemType<T> conmonItemType,通過這個來獲取不同的布局,從而獲取到不同的viewholer,看看怎么使用:
1 package com.example.administrator.recylerviewadaptertest; 2 3 import android.app.Activity; 4 import android.support.v7.app.AppCompatActivity; 5 import android.os.Bundle; 6 import android.support.v7.widget.LinearLayoutManager; 7 import android.support.v7.widget.RecyclerView; 8 import android.util.Log; 9 import android.widget.TextView; 10 11 import java.util.ArrayList; 12 import java.util.List; 13 14 public class MainActivity extends Activity { 15 private RecyclerView recycler; 16 private BaseRecyclerAdapter mAdapter; 17 private List<String> stringList = new ArrayList<String>(); 18 19 20 private MultiItemCommonAdapter adapter; 21 private int typeOne = 1; 22 private int typeTwo = 2; 23 24 @Override 25 protected void onCreate(Bundle savedInstanceState) { 26 super.onCreate(savedInstanceState); 27 setContentView(R.layout.activity_main); 28 29 recycler = findViewById(R.id.recycler); 30 31 /** 32 * 普通的列表形式 33 */ 34 // mAdapter = new BaseRecyclerAdapter<String>(this, R.layout.rl_item_view, stringList) { 35 // @Override 36 // public void convert(BaseViewHolder holder, String s) { 37 // holder.setText(R.id.test, s); 38 // } 39 // }; 40 // 41 // LinearLayoutManager manager = new LinearLayoutManager(this); 42 // recycler.setLayoutManager(manager); 43 // recycler.setAdapter(mAdapter); 44 // 45 // 46 // for (int i = 0; i < 50; i++) { 47 // stringList.add("測試-->" + i); 48 // } 49 // mAdapter.notifyDataSetChanged(); 50 51 52 /** 53 * 不同item布局的形式 54 */ 55 BaseRecyclerAdapter.ConmonItemType conmonItemType = new BaseRecyclerAdapter.ConmonItemType<String>() { 56 57 @Override 58 public int getLayoutId(int itemType) { 59 if (itemType == typeOne) { 60 return R.layout.item_one; 61 } else { 62 return R.layout.item_two; 63 } 64 } 65 66 @Override 67 public int getItemViewType(int position, String s) { 68 if (position == 0) { 69 return typeOne; 70 } else { 71 return typeTwo; 72 } 73 } 74 }; 75 76 77 for (int i = 0; i < 2; i++) { 78 stringList.add("測試-->" + i); 79 } 80 81 82 adapter = new MultiItemCommonAdapter<String>(this, stringList, conmonItemType) { 83 @Override 84 public void convert(BaseViewHolder holder, String s) { 85 if (holder.getItemViewType() == 0) { 86 //Todo 87 88 } else { 89 //Todo 90 } 91 } 92 }; 93 LinearLayoutManager manager = new LinearLayoutManager(this); 94 recycler.setLayoutManager(manager); 95 recycler.setAdapter(adapter); 96 97 } 98 }
在這里我是自己定義的typeone,和typetwo,在項目中我們可以根據bean來進行判斷,不同的類型,返回不同的值,從而獲取不同的item布局,ok,這樣的話,我們的多種ItemViewType的支持也就完成了
源碼鏈接:https://github.com/343661629/RecyclerView-