標籤:
一般來說,ListView的清單項目都會採用相同的布局,只是填充的內容不同而已,這種情況下,Android提供了convertView幫我們緩衝清單項目,達到迴圈利用的目的,開發人員也會使用ViewHolder模式來對ListView進行最佳化。但有的情況下,ListView的清單項目布局是不盡相同的,甚至差別很大,這時就不能簡單的使用同一個布局資源檔來表示不同類型的清單項目了,而是必須區別對待。典型的情況如Android狀態通知欄,如所示。
360安全衛士、唱吧,閃推這三款應用在狀態通知欄的布局差別很大,那麼我們又想使用同一個Adapter來表示不同清單項目,這時就需要在Adapter中使用容器來包含這些不同的View了。這裡定義SackOfViewAdapter類,繼承BaseAdapter,在該類中定義容器變數mViewList來儲存ListView中不同清單項目的view;同時,定義兩個建構函式,一個是在參數中指定容器的大小,並填充null值;一個則直接傳入ListView清單項目中所有view的集合。代碼如下:
SackOfViewAdapter類的關鍵代碼在newView函數和getView函數,其中newView函數用於給容器變數mViewList中值為null的元素賦值,一般由SackOfViewAdapter的子類實現。而getView函數重寫自BaseAdapter類,是Adapter返回View類執行個體的關鍵函數,代碼如下所示:
SackOfViewAdapter類的完整代碼如下所示:
- public class SackOfViewsAdapter extends BaseAdapter {
-
- private List<View> mViewList = null;
-
- /**
- * 構造大小為count,值為null的view集合,這時需要子類重寫newView函數
- */
- public SackOfViewsAdapter(int count) {
- super();
- mViewList = new ArrayList<View>(count);
- for (int i = 0; i < count; i++) {
- mViewList.add(null);
- }
- }
-
- /**
- * 由傳入的view集合直接給容器賦值,如果view集合中有為null值的view,則子類必須實現newView函數
- */
- public SackOfViewsAdapter(List<View> views) {
- super();
- this.mViewList = views;
- }
-
- /**
- * 返回對應位置的清單項目
- */
- @Override
- public Object getItem(int position) {
- return mViewList.get(position);
- }
-
- /**
- * 返回清單項目的個數
- */
- @Override
- public int getCount() {
- return mViewList.size();
- }
-
- /**
- * getView函數建立的清單項目類型個數
- */
- @Override
- public int getViewTypeCount() {
- return getCount();
- }
-
- /**
- * getView函數建立的view類型值,這裡以view所在的位置作為類型值
- */
- @Override
- public int getItemViewType(int position) {
- return position;
- }
-
- /**
- * 如果Adapter中所有清單項目都是可點擊和可選擇的,則返回true
- */
- @Override
- public boolean areAllItemsEnabled() {
- return false;
- }
-
- /**
- * 如果position所指的清單項目不是分隔字元,則返回true
- */
- @Override
- public boolean isEnabled(int position) {
- return false;
- }
-
- /**
- * 返回指定位置position的清單項目的view
- */
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- View result = mViewList.get(position);
-
- // 如果mViewList中的view為null,則需要調用newView函數來建立一個,該函數由子類來實現
- if (result == null) {
- result = newView(position, parent);
- mViewList.set(position, result);
- }
-
- return result;
- }
-
- /**
- * 建立列表中指定位置的清單項目,該函數有子類實現
- */
- protected View newView(int position, ViewGroup parent) {
- throw new RuntimeException("You must override newView()!");
- }
-
- /**
- * 獲得指定位置的清單項目的id
- */
- @Override
- public long getItemId(int position) {
- return position;
- }
-
- /**
- * 判斷Adapter中是否存在某個指定的view
- */
- public boolean hasView(View v) {
- return mViewList.contains(v);
- }
-
- }
最後,以一個執行個體來說明SackOfViewAdapter類的使用方法,執行個體中我們定義4個不同布局的清單項目,其中一個為null值,由SackOfViewAdapter的子類重寫newView函數實現賦值,其他三個則不是null值。這四個view的布局檔案分別是main_notify.xml、update_progress_notify.xml、notification_battery.xml和main_notify_red.xml,這些資源借用自360手機衛士,執行個體效果如所示:
而執行個體的代碼如下:
- public class SackOfViewsDemo extends ListActivity {
-
- @Override
- public void onCreate(Bundle bundle) {
- super.onCreate(bundle);
- requestWindowFeature(Window.FEATURE_NO_TITLE);
- setContentView(R.layout.main);
-
- ArrayList<View> views = new ArrayList<View>();
-
- LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- // 清單項目1
- View view = inflater.inflate(R.layout.main_notify, null);
- views.add(view);
-
- // 清單項目2
- view = inflater.inflate(R.layout.update_progress_notify, null);
- views.add(view);
-
- // 清單項目3
- view = inflater.inflate(R.layout.notification_battery, null);
- views.add(view);
-
- // 清單項目4(為null值,在newView函數中建立)
- views.add(null);
-
- setListAdapter(new SillyAdapter(views));
- }
-
- class SillyAdapter extends SackOfViewsAdapter {
- public SillyAdapter(List<View> views) {
- super(views);
- }
-
- protected View newView(int position, ViewGroup parent) {
- LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- View view = inflater.inflate(R.layout.main_notify_red, null);
- return view;
- }
- }
- }
本文的SackOfViewAdapter類參考自 https://github.com/commonsguy/cwac-sacklist
本文源碼參見:http://download.csdn.net/detail/ace1985/4575749
Android開原始碼解讀-基於SackOfViewAdapter類實作類別似狀態通知欄的布局