編輯:Android技術基礎
如題,本節給大家帶來的是構建一個可復用的自定義BaseAdapter,我們每每涉及到ListView GridView等其他的Adapter控件,都需要自己另外寫一個BaseAdapter類,這樣顯得非常麻煩, 又比如,我們想在一個界面顯示兩個ListView的話,我們也是需要些兩個BaseAdapter... 這,程序員都是喜歡偷懶的哈,這節我們就來寫一個可復用的自定義BaseAdapter類~
首先我們把上節寫的自定義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; } }
好的,畢竟我們傳遞過來的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!
我們先來看看前面我們的ViewHolder干了什麼? 答:findViewById,設置控件狀態; 下面我們想在完成這個基礎上,將getView()方法大部分的邏輯寫到ViewHolder類裡, 這個ViewHolder要做的事:
- 定義一個查找控件的方法,我們的思路是通過暴露公共的方法,調用方法時傳遞過來 控件id,以及設置的內容,比如TextView設置文本: public ViewHolder setText(int id, CharSequence text){文本設置}
- 將convertView復用部分搬到這裡,那就需要傳遞一個context對象了,我們把需要獲取 的部分都寫到構造方法中!
- 寫一堆設置方法(public),比如設置文字大小顏色,圖片背景等!
好的,接下來我們就來一步步改造我們的ViewHolder類
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; }
在上面的基礎上我們再添加一個綁定的方法
//綁定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; }
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; } //其他方法可自行擴展
好的,ViewHolder的改造升級完成~
public abstract void bindView(ViewHolder holder, T obj);
我們創建新的BaseAdapter的時候,實現這個方法就好,另外,別忘了把我們自定義 的BaseAdapter改成abstact抽象的!
@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(); }
我們要實現的效果圖:
就是上面有兩個列表,布局不一樣,但是我只使用一個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的使用就如上面所述~
ListViewDemo4.zip
貼下最後寫好的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; } //其他方法可自行擴展 } }
本節給大家介紹了如何來實現一個可供復用的BaseAdapter,當然大家可以在這個的基礎上根據 自己的需求進行修改,比如通過異步設置網絡圖片等~改代碼是參考鴻洋大神的視頻寫的: 視頻鏈接:Android-打造萬能適配器 另外,實際編寫中遇到一些問題,非常感謝Berial(B神)的耐心點撥~ ありがとうございます~
通過Intent完成短信發送,其本質也是調用Android系統自帶發送短信程序,不是真正的自定義發送。如果想實現真正意義的自定義發送,則要采用Service的方式。一、設
事件,我們並不陌生!所有的基於UI的應用程序,事件都變得不可或缺!試想一下,如果我們做的程序單擊按鈕和其它控件都沒有反應,那麼就如同一個人在這個世界上聽不到聲音一樣!An
我在項目中用到了二維碼掃描的技術,用的是Google提供的ZXing開源項目,它提供二維碼和條形碼的掃描。掃描條形碼就是直接讀取條形碼的內容,掃描二維碼是按照自己指定的二
時間分為指針和數字兩種,如果Android應用中用到時鐘,僅需要使用指針時鐘AnlogClock與數字時鐘DigitalClock即可,不需要編程。 當然如果你對系統的