轉載自http://www.runoob.com/w3cnote/android-tutorial-customer-baseadapter.html 作者:coder-pig 本節引言: 如題,本節給大家帶來的是構建一個可復用的自定義BaseAdapter,我們每每涉及到ListView Grid ...
轉載自http://www.runoob.com/w3cnote/android-tutorial-customer-baseadapter.html 作者:coder-pig
本節引言:
如題,本節給大家帶來的是構建一個可復用的自定義BaseAdapter,我們每每涉及到ListView GridView等其他的Adapter控制項,都需要自己另外寫一個BaseAdapter類,這樣顯得非常麻煩, 又比如,我們想在一個界面顯示兩個ListView的話,我們也是需要些兩個BaseAdapter... 這,程式員都是喜歡偷懶的哈,這節我們就來寫一個可復用的自定義BaseAdapter類~
1.我們一點點開始改:
首先我們把上節寫的自定義BaseAdapter貼下,等下我們就要對他進行升級改造
/** * Created by Jay on 2015/9/21 0021. */ public class MyAdapter extends BaseAdapter { private Context mContext; private LinkedList<Data> mData; public MyAdapter() { } public MyAdapter(LinkedList<Data> mData, Context mContext) { this.mData = mData; this.mContext = mContext; } @Override public int getCount() { return mData.size(); } @Override public Object getItem(int position) { return null; } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder = null; if (convertView == null) { convertView = LayoutInflater.from(mContext).inflate(R.layout.item_list, parent, false); holder = new ViewHolder(); holder.img_icon = (ImageView) convertView.findViewById(R.id.img_icon); holder.txt_content = (TextView) convertView.findViewById(R.id.txt_content); convertView.setTag(holder); } else { holder = (ViewHolder) convertView.getTag(); } holder.img_icon.setImageResource(mData.get(position).getImgId()); holder.txt_content.setText(mData.get(position).getContent()); return convertView; } //添加一個元素 public void add(Data data) { if (mData == null) { mData = new LinkedList<>(); } mData.add(data); notifyDataSetChanged(); } //往特定位置,添加一個元素 public void add(int position,Data data){ if (mData == null) { mData = new LinkedList<>(); } mData.add(position, data); notifyDataSetChanged(); } public void remove(Data data) { if(mData != null) { mData.remove(data); } notifyDataSetChanged(); } public void remove(int position) { if(mData != null) { mData.remove(position); } notifyDataSetChanged(); } public void clear() { if(mData != null) { mData.clear(); } notifyDataSetChanged(); } private class ViewHolder { ImageView img_icon; TextView txt_content; } }
升級1:將Entity設置成泛型
好的,畢竟我們傳遞過來的Entitiy實體類可能千奇百怪,比如有Person,Book,Wether等,所以我們 將Entity設置成泛型,修改後的代碼如下:
public class MyAdapter<T> extends BaseAdapter { private Context mContext; private LinkedList<T> mData; public MyAdapter() { } public MyAdapter(LinkedList<T> mData, Context mContext) { this.mData = mData; this.mContext = mContext; } @Override public int getCount() { return mData.size(); } @Override public Object getItem(int position) { return null; } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder = null; if (convertView == null) { convertView = LayoutInflater.from(mContext).inflate(R.layout.item_list, parent, false); holder = new ViewHolder(); holder.img_icon = (ImageView) convertView.findViewById(R.id.img_icon); holder.txt_content = (TextView) convertView.findViewById(R.id.txt_content); convertView.setTag(holder); } else { holder = (ViewHolder) convertView.getTag(); } holder.img_icon.setImageResource(mData.get(position).getImgId()); holder.txt_content.setText(mData.get(position).getContent()); return convertView; } //添加一個元素 public void add(T data) { if (mData == null) { mData = new LinkedList<>(); } mData.add(data); notifyDataSetChanged(); } //往特定位置,添加一個元素 public void add(int position,T data){ if (mData == null) { mData = new LinkedList<>(); } mData.add(position, data); notifyDataSetChanged(); } public void remove(T data) { if(mData != null) { mData.remove(data); } notifyDataSetChanged(); } public void remove(int position) { if(mData != null) { mData.remove(position); } notifyDataSetChanged(); } public void clear() { if(mData != null) { mData.clear(); } notifyDataSetChanged(); } private class ViewHolder { ImageView img_icon; TextView txt_content; } }
好的,上面我們做的事僅僅是將Data類型換成了泛型T!
升級2:ViewHolder類的升級改造:
我們先來看看前面我們的ViewHolder幹了什麼? 答:findViewById,設置控制項狀態; 下麵我們想在完成這個基礎上,將getView()方法大部分的邏輯寫到ViewHolder類里, 這個ViewHolder要做的事:
- 定義一個查找控制項的方法,我們的思路是通過暴露公共的方法,調用方法時傳遞過來 控制項id,以及設置的內容,比如TextView設置文本: public ViewHolder setText(int id, CharSequence text){文本設置}
- 將convertView復用部分搬到這裡,那就需要傳遞一個context對象了,我們把需要獲取 的部分都寫到構造方法中!
- 寫一堆設置方法(public),比如設置文字大小顏色,圖片背景等!
好的,接下來我們就來一步步改造我們的ViewHolder類
1)相關參數與構造方法:
public static class ViewHolder { private SparseArray<View> mViews; //存儲ListView 的 item中的View private View item; //存放convertView private int position; //游標 private Context context; //Context上下文 //構造方法,完成相關初始化 private ViewHolder(Context context, ViewGroup parent, int layoutRes) { mViews = new SparseArray<>(); this.context = context; View convertView = LayoutInflater.from(context).inflate(layoutRes, parent,false); convertView.setTag(this); item = convertView; } ImageView img_icon; TextView txt_content; }
2)綁定ViewHolder與Item
在上面的基礎上我們再添加一個綁定的方法
//綁定ViewHolder與item public static ViewHolder bind(Context context, View convertView, ViewGroup parent, int layoutRes, int position) { ViewHolder holder; if(convertView == null) { holder = new ViewHolder(context, parent, layoutRes); } else { holder = (ViewHolder) convertView.getTag(); holder.item = convertView; } holder.position = position; return holder; }
3)根據id獲取集合中保存的控制項
public <T extends View> T getView(int id) { T t = (T) mViews.get(id); if(t == null) { t = (T) item.findViewById(id); mViews.put(id, t); } return t; }
4) 接著我們再定義一堆暴露出來的方法
/** * 獲取當前條目 */ public View getItemView() { return item; } /** * 獲取條目位置 */ public int getItemPosition() { return position; } /** * 設置文字 */ public ViewHolder setText(int id, CharSequence text) { View view = getView(id); if(view instanceof TextView) { ((TextView) view).setText(text); } return this; } /** * 設置圖片 */ public ViewHolder setImageResource(int id, int drawableRes) { View view = getView(id); if(view instanceof ImageView) { ((ImageView) view).setImageResource(drawableRes); } else { view.setBackgroundResource(drawableRes); } return this; } /** * 設置點擊監聽 */ public ViewHolder setOnClickListener(int id, View.OnClickListener listener) { getView(id).setOnClickListener(listener); return this; } /** * 設置可見 */ public ViewHolder setVisibility(int id, int visible) { getView(id).setVisibility(visible); return this; } /** * 設置標簽 */ public ViewHolder setTag(int id, Object obj) { getView(id).setTag(obj); return this; } //其他方法可自行擴展
好的,ViewHolder的改造升級完成~
升級3:定義一個抽象方法,完成ViewHolder與Data數據集的綁定
public abstract void bindView(ViewHolder holder, T obj);
我們創建新的BaseAdapter的時候,實現這個方法就好,另外,別忘了把我們自定義 的BaseAdapter改成abstact抽象的!
升級4:修改getView()部分的內容
@Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder = ViewHolder.bind(parent.getContext(), convertView, parent, mLayoutRes , position); bindView(holder,getItem(position)); return holder.getItemView(); }
2.升級完畢,我們寫代碼來體驗下:
我們要實現的效果圖:
就是上面有兩個列表,佈局不一樣,但是我只使用一個BaseAdapter類來完成上述效果!
關鍵代碼如下:
MainActivity.java:
public class MainActivity extends AppCompatActivity { private Context mContext; private ListView list_book; private ListView list_app; private MyAdapter<App> myAdapter1 = null; private MyAdapter<Book> myAdapter2 = null; private List<App> mData1 = null; private List<Book> mData2 = null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mContext = MainActivity.this; init(); } private void init() { list_book = (ListView) findViewById(R.id.list_book); list_app = (ListView) findViewById(R.id.list_app); //數據初始化 mData1 = new ArrayList<App>(); mData1.add(new App(R.mipmap.iv_icon_baidu,"百度")); mData1.add(new App(R.mipmap.iv_icon_douban,"豆瓣")); mData1.add(new App(R.mipmap.iv_icon_zhifubao,"支付寶")); mData2 = new ArrayList<Book>(); mData2.add(new Book("《第一行代碼Android》","郭霖")); mData2.add(new Book("《Android群英傳》","徐宜生")); mData2.add(new Book("《Android開發藝術探索》","任玉剛")); //Adapter初始化 myAdapter1 = new MyAdapter<App>((ArrayList)mData1,R.layout.item_one) { @Override public void bindView(ViewHolder holder, App obj) { holder.setImageResource(R.id.img_icon,obj.getaIcon()); holder.setText(R.id.txt_aname,obj.getaName()); } }; myAdapter2 = new MyAdapter<Book>((ArrayList)mData2,R.layout.item_two) { @Override public void bindView(ViewHolder holder, Book obj) { holder.setText(R.id.txt_bname,obj.getbName()); holder.setText(R.id.txt_bauthor,obj.getbAuthor()); } }; //ListView設置下Adapter: list_book.setAdapter(myAdapter2); list_app.setAdapter(myAdapter1); } }
我們寫的可復用的BaseAdapter的使用就如上面所述~
3.代碼示例下載:
貼下最後寫好的MyAdapter類吧,可根據自己的需求進行擴展:
MyAdapter.java:
/** * Created by Jay on 2015/9/22 0022. */ public abstract class MyAdapter<T> extends BaseAdapter { private ArrayList<T> mData; private int mLayoutRes; //佈局id public MyAdapter() { } public MyAdapter(ArrayList<T> mData, int mLayoutRes) { this.mData = mData; this.mLayoutRes = mLayoutRes; } @Override public int getCount() { return mData != null ? mData.size() : 0; } @Override public T getItem(int position) { return mData.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder = ViewHolder.bind(parent.getContext(), convertView, parent, mLayoutRes , position); bindView(holder, getItem(position)); return holder.getItemView(); } public abstract void bindView(ViewHolder holder, T obj); //添加一個元素 public void add(T data) { if (mData == null) { mData = new ArrayList<>(); } mData.add(data); notifyDataSetChanged(); } //往特定位置,添加一個元素 public void add(int position, T data) { if (mData == null) { mData = new ArrayList<>(); } mData.add(position, data); notifyDataSetChanged(); } public void remove(T data) { if (mData != null) { mData.remove(data); } notifyDataSetChanged(); } public void remove(int position) { if (mData != null) { mData.remove(position); } notifyDataSetChanged(); } public void clear() { if (mData != null) { mData.clear(); } notifyDataSetChanged(); } public static class ViewHolder { private SparseArray<View> mViews; //存儲ListView 的 item中的View private View item; //存放convertView private int position; //游標 private Context context; //Context上下文 //構造方法,完成相關初始化 private ViewHolder(Context context, ViewGroup parent, int layoutRes) { mViews = new SparseArray<>(); this.context = context; View convertView = LayoutInflater.from(context).inflate(layoutRes, parent, false); convertView.setTag(this); item = convertView; } //綁定ViewHolder與item public static ViewHolder bind(Context context, View convertView, ViewGroup parent, int layoutRes, int position) { ViewHolder holder; if (convertView == null) { holder = new ViewHolder(context, parent, layoutRes); } else { holder = (ViewHolder) convertView.getTag(); holder.item = convertView; } holder.position = position; return holder; } @SuppressWarnings("unchecked") public <T extends View> T getView(int id) { T t = (T) mViews.get(id); if (t == null) { t = (T) item.findViewById(id); mViews.put(id, t); } return t; } /** * 獲取當前條目 */ public View getItemView() { return item; } /** * 獲取條目位置 */ public int getItemPosition() { return position; } /** * 設置文字 */ public ViewHolder setText(int id, CharSequence text) { View view = getView(id); if (view instanceof TextView) { ((TextView) view).setText(text); } return this; } /** * 設置圖片 */ public ViewHolder setImageResource(int id, int drawableRes) { View view = getView(id); if (view instanceof ImageView) { ((ImageView) view).setImageResource(drawableRes); } else { view.setBackgroundResource(drawableRes); } return this; } /** * 設置點擊監聽 */ public ViewHolder setOnClickListener(int id, View.OnClickListener listener) { getView(id).setOnClickListener(listener); return this; } /** * 設置可見 */ public ViewHolder setVisibility(int id, int visible) { getView(id).setVisibility(visible); return this; } /** * 設置標簽 */ public ViewHolder setTag(int id, Object obj) { getView(id).setTag(obj); return this; } //其他方法可自行擴展 } }