封裝能重用的自定義Adapter,向翔哥致敬
來源:程序員人生 發(fā)布時(shí)間:2015-06-24 07:59:35 閱讀次數(shù):4378次
看了翔哥的自定義萬能的adapter,自己也做下筆記,分析1下高手的思惟方式,讓我們1起進(jìn)入變態(tài)程序員的內(nèi)心世界。
分析萬能的adapter之前,我們先分析1下普通的adapter
public class ReportSpinnerAdapter extends BaseAdapter {
private Context context;
private List<String> str;
public ReportSpinnerAdapter(Context context, List<String> str, int textWidth) {
this.context = context;
this.str = str;
this.textWidth = textWidth;
}
@Override
public int getCount() {
return str.size();
}
@Override
public Object getItem(int position) {
return str.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
Viewholder hold;
if (convertView==null){
convertView = LayoutInflater.from(context).inflate(R.layout.spinner_layout,parent,false);
hold = new ViewHold();
hold.textView = (TextView) convertView.findViewById(R.id.textView);
convertView.setTag(hold);
}else{
hold = (ViewHold) convertView.getTag();
}
hold.textView.setText(str.get(position));
return convertView;
}
static class ViewHolder{
TextView textView;
}
普通的adapter大致就分為兩點(diǎn),getView和ViewHolder,1個(gè)類就解決問題,觸及到控件的復(fù)用,就用到了ViewHolder,主要邏輯還是都在getView中,,如果對(duì)這個(gè)不理解,可以先百度ViewHolder,getView中的邏輯就是如果convertView第1次被使用的時(shí)候,初始化綁定布局,并設(shè)置標(biāo)記,否則,就從convertView取出viewHolder,如果要更改布局中控件的參數(shù)就從viewHolder中取出控件設(shè)置參數(shù),由于這個(gè)控件在convertView初始化的時(shí)候就1起初始化了,所以直接設(shè)置參數(shù)就ok了。這是1個(gè)標(biāo)準(zhǔn)程序員的通常做法,但是,這樣如果我們程序中要常常使用adapter,每一個(gè)Listview或GridView都要去弄1個(gè)adapter,就白白浪費(fèi)了大量的時(shí)間,作為1個(gè)變態(tài)程序員,翔哥怎樣能忍,所以就出了這么1篇博客翔哥博客,讓我們也能從中獲利,收獲了新技術(shù)也收獲了新的思惟方式。
總結(jié)自定義萬能的adapter,或叫做可重用的adapter,分拆開來看,就是3點(diǎn):
1.封裝1個(gè)特殊的ViewHolder,可以傳入?yún)?shù)就直接得到viewHolder,把這步干掉:
if (convertView==null){
convertView = LayoutInflater.from(context).inflate(R.layout.spinner_layout,parent,false);
hold = new ViewHold();
hold.textView = (TextView) convertView.findViewById(R.id.textView);
convertView.setTag(hold);
}else{
hold = (ViewHold) convertView.getTag();
}
想要干掉這1步,就要想到,傳入甚么樣的參數(shù),才能直接得到viewHolder呢,就是后面這幾個(gè),1.LayoutInflater.from(context) 2.R.layout.spinner_layout 3.parent 4.convertView
知道了需要的條件就好說了,直接寫1個(gè)
public class ViewHolder {
private SparseArray<View> views;
private View convertView;
public ViewHolder(ViewGroup parent,LayoutInflater inflater,int layoutId) {
this.views = new SparseArray<View>();
this.convertView = inflater.inflate(layoutId,parent,false);
this.convertView.setTag(this);
}
/**
* 得到viewHolder
* @param parent
* @param convertView
* @param inflater
* @param layoutId
* @return
*/
public static ViewHolder getViewHolder(ViewGroup parent,View convertView,LayoutInflater inflater,int layoutId){
if (convertView==null){
return new ViewHolder(parent,inflater,layoutId);
}
return (ViewHolder) convertView.getTag();
}
這個(gè) SparseArray<View> views實(shí)際上就是1個(gè)鍵值對(duì),用來保存listview或gridview上每行或每列上的所有控件的,效力上要高于hashmap,用法就是
/**
* 根據(jù)Id得到view
* @param viewId
* @param <T>
* @return
*/
public <T extends View>T getView(int viewId){
View view = views.get(viewId);
if (view==null){
view = convertView.findViewById(viewId);
views.put(viewId,view);
}
return (T) view;
}
這樣,1個(gè)ViewHolder就弄定了。
2.編寫1個(gè)通用的adapter,通用adapter,基本沒法實(shí)現(xiàn),那怎樣辦呢,做1個(gè)半通用的adapter,既然要半通用,就是大體相同,少數(shù)差異,那用抽象類繼承的方式就最好了
public abstract class CommonAdapter<T> extends BaseAdapter {
private List<T> list;
private LayoutInflater inflater;
private int layoutId;
public CommonAdapter(List<T> list, Context context,int layoutId) {
this.list = list;
this.inflater = LayoutInflater.from(context);
this.layoutId = layoutId;
}
@Override
public int getCount() {
return list.size();
}
@Override
public Object getItem(int position) {
return list.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder = ViewHolder.getViewHolder(parent,convertView,inflater,layoutId);
convert(viewHolder,list.get(position));
return viewHolder.getConvertView();
}
public abstract void convert(ViewHolder viewHolder,T t);
}
首先,我們綁定adapter的時(shí)候不肯定數(shù)據(jù)源,就得用泛型類和泛型集合了,再就是傳入布局id和context上下文,把需要給控件賦值的地方設(shè)置為抽象方法,給子類繼承,這樣封裝好了以后,我們需要做的事情就是少之又少了,只需要重寫convert方法和構(gòu)造方法了
public class MyAdapter extends CommonAdapter<Bean> {
public MyAdapter(List<Bean> list, Context context, int layoutId) {
super(list, context, layoutId);
}
@Override
public void convert(ViewHolder viewHolder, Bean bean) {
((TextView)viewHolder.getView(R.id.text)).setText("這是測(cè)試數(shù)據(jù)1");
((TextView)viewHolder.getView(R.id.text)).setText("這是測(cè)試數(shù)據(jù)1"); }
}
這樣,只需要在activity或fragment中進(jìn)行綁定MyAdapter,把數(shù)據(jù)和布局id和content傳入就弄定了。只不過(viewHolder.getView(R.id.text)).setText這類寫法很蛋疼,代碼中寫強(qiáng)轉(zhuǎn)的話,還要把光標(biāo)切回來,反正我個(gè)人是很不習(xí)慣的,那怎樣辦呢,可以這樣,我們既然有了viewholder對(duì)象,我們就改造1下viewHolder對(duì)象,讓公共代碼多1點(diǎn),我們以后重復(fù)寫的地方就少1點(diǎn)。在ViewHolder中加入以下方法
/**
* 根據(jù)id得到TextView
* @return
*/
public TextView getTextView(int viewId){
return getView(viewId);
}
/**
* 根據(jù)id得到ImageView
* @return
*/
public ImageView getImageView(int viewId){
return getView(viewId);
}
/**
* 根據(jù)id得到Button
* @return
*/
public Button getButton(int viewId){
return getView(viewId);
}
/**
* 根據(jù)id得到RadioButton
* @return
*/
public RadioButton getRadioButton(int viewId){
return getView(viewId);
}
/**
* 根據(jù)id得到CheckBox
* @return
*/
public CheckBox getCheckBox(int viewId){
return getView(viewId);
}
/**
* 根據(jù)id得到ImageButton
* @return
*/
public ImageButton getImageButton(int viewId){
return getView(viewId);
}
/**
* 根據(jù)id得到ImageButton
* @return
*/
public EditText getEditText(int viewId){
return getView(viewId);
}
那末我們的Myadapter中的convert方法就能夠這樣寫了
@Override
public void convert(ViewHolder viewHolder, Bean bean) {
viewHolder.getTextView(R.id.text).setText("這是測(cè)試數(shù)據(jù)1");
viewHolder.getTextView(R.id.text).setText("這是測(cè)試數(shù)據(jù)2");
}
這樣書寫起來就會(huì)流暢1點(diǎn),比較跟手,好了,這基本就是翔哥萬能的自定義adapter的主要內(nèi)容,下面圖解1下核心思想
最后,源碼:點(diǎn)擊打開鏈接
生活不易,碼農(nóng)辛苦
如果您覺得本網(wǎng)站對(duì)您的學(xué)習(xí)有所幫助,可以手機(jī)掃描二維碼進(jìn)行捐贈(zèng)