作為一名編程初學者,我總是認為自己什么都不會,什么都不行,就算實現了文檔指定的功能,我永遠都是覺得自己寫過的代碼實在是太爛了,它只是恰巧能夠運行而已!它只是在運行的時候恰巧沒有發現錯誤而已!!一直都是抱着這樣的念頭,但迫於工作進度以及工作心情(這點必須承認,被上頭追着進度的感覺讓人很郁悶),在項目完結的一段時間內都不想看到自己的代碼!!所以,迫切提醒各位和我一樣的菜鳥,不要放過每一次重構和優化的機會,這種優化可以是小步驟的,有時就是代碼結構的一個優化,或者是某個變量名的修改,並不要求我們從一開始就對結構進行優化,記住這句話:
程序員只要對自己的代碼負責就行。
自己寫過的代碼遲早是要被人看的,被人用的,所以,它就像是我們在這圈子里的名片,無論我們把自己吹得再牛,一看我們的代碼,就真的是什么餡都清楚了。所以,不要對自己正在寫的代碼馬虎,最后吃虧的是自己。
在結束項目的某個進度后,就來寫寫博客轉換一下心情,想起常用控件ListView,於是就來研究研究它。
使用ListView關鍵的就是適配器,可怕的是,用於ListView的適配器很多。
我們先從名字看似最簡單其實不簡單的SimpleAdapter開始。
我們先來看一個簡單的例子:
private ListView mListView; private LinearLayout mLayout; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mLayout = new LinearLayout(this); mLayout.setOrientation(LinearLayout.VERTICAL); mListView = new ListView(this); LinearLayout.LayoutParams param = new LinearLayout.LayoutParams( LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT); mLayout.addView(mListView, param); setContentView(mLayout); Map<String, String> keyValuePair = new HashMap<String, String>(); keyValuePair.put("Name", "小智"); keyValuePair.put("Age", "10"); List<Map<String, String>> list = new ArrayList<Map<String, String>>(); list.add(keyValuePair); ListAdapter adapter = new SimpleAdapter(this, list, android.R.layout.simple_list_item_2, new String[] { "Name", "Age" }, new int[] { android.R.id.text1, android.R.id.text2 }); mListView.setAdapter(adapter); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; }
我們先從SimpleAdapter的構造開始。
要構造一個SimpleAdapter,需要以下的參數:
1.Context context:上下文,這個是每個組件都需要的,它指明了SimpleAdapter關聯的View的運行環境,也就是我們當前的Activity。
2.List<? extends Map<String, ?>> data:這是一個由Map組成的List,在該List中的每個條目對應ListView的一行,每一個Map中包含的就是所有在from參數中指定的key。
3.int resource:定義列表項的布局文件的資源ID,該資源文件至少應該包含在to參數中定義的ID。
4.String[] from:將被添加到Map映射上的key。
5.int[] to:將綁定數據的視圖的ID跟from參數對應,這些被綁定的視圖元素應該全是TextView。
上面的例子中我們是手動的添加視圖,然后使用的是系統默認的視圖元素,像是android.R.id.text1。當然,我們也可以自定義TextView的樣式,而且,說是應該全是TextView,也只是應該,並不是絕對的:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ListView listView = (ListView) this.findViewById(R.id.list); List<Map<String, ?>> list = new ArrayList<Map<String, ?>>(); for (int i = 0; i < 5; i++) { Map<String, String> keyValuePair = new HashMap<String, String>(); keyValuePair.put("Text", "Text" + i); keyValuePair.put("Button", "Button" + i); list.add(keyValuePair); } ListAdapter adapter = new SimpleAdapter(this, list, R.layout.listitem, new String[] { "Text", "Button" }, new int[] { R.id.text, R.id.button }); listView.setAdapter(adapter);
從這里我們可以看到,要想使用ListView,我們應用程序的主界面必須包含ListView,然后ListView的內容可以自己定義,而不僅僅是TextView。
要想知道這是什么回事,我們就要知道SimpleAdapter是如何綁定數據到視圖的,這個過程我們甚至可以自定義:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ListView listView = (ListView) this.findViewById(R.id.list); List<Map<String, String>> list = new ArrayList<Map<String, String>>(); for (int i = 0; i < 3; i++) { Map<String, String> keyValuePair = new HashMap<String, String>(); keyValuePair.put("text", "text" + i); list.add(keyValuePair); } CustomSimpleAdapter adapter = new CustomSimpleAdapter(this, list, R.layout.listitem); listView.setAdapter(adapter);
class CustomSimpleAdapter extends SimpleAdapter { private int mResource; private List<? extends Map<String, ?>> mData; public CustomSimpleAdapter(Context context, List<? extends Map<String, ?>> data, int resource) { super(context, data, resource, null, null); this.mResource = resource; this.mData = data; } @Override public View getView(int position, View convertView, ViewGroup group) { LayoutInflater layoutInflater = getLayoutInflater(); View view = layoutInflater.inflate(mResource, null); TextView text = (TextView) view.findViewById(R.id.text); text.setText(mData.get(position).get("text").toString()); if (position == 2) { text.setTextColor(Color.RED); } return view; } }
要想實現自定義的ListView,最主要的是實現getView(),因為SimpleAdapter的數據綁定就是發生在這里。
現在我們可以總結一下SimpleAdapter的數據綁定是怎樣的:利用傳入的view(該view包含ListView每行要渲染的視圖元素)的ResourceID得到該view,然后通過每個vie所在的索引,也就是它們的行數,得到data中相應內容的key,接着就是利用這些key的value填充這些視圖元素,最后返回view作為ListView每行的內容顯示出來。
由此可見,from和to並不是必須的,要想實現ListView,前三個參數才是必要的,也許大家會看到網上有些例子為了實現自定義的SimpleAdapter,會覆寫它的許多方法,其實如果單純只是想要利用SimpleAdapter來實現自定義的ListView,只要覆寫getView()就行,其他的完全可以交給SimpleAdapter原先的方法來做,除非我們有特殊的要求。
SimpleAdapter並不僅僅用在ListView上,事實上,Spinner同樣可以使用:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Spinner spinner = (Spinner) this.findViewById(R.id.spinner); List<Map<String, ?>> list = new ArrayList<Map<String, ?>>(); for (int i = 0; i < 5; i++) { Map<String, String> keyValuePair = new HashMap<String, String>(); keyValuePair.put("Text", "Text" + i); list.add(keyValuePair); } SimpleAdapter adapter = new SimpleAdapter(this, list, R.layout.listitem, new String[] { "Text" }, new int[] { R.id.text }); spinner.setAdapter(adapter); }
因為Spinner顯示的列表本質上就是一個ListView,所以,和ListView有關的一切它幾乎都可以使用,這個還是放在Spinner那時候再講吧。
原本只是想要將所有的適配器講完,但礙於篇幅有限,所以只好分開講,還有,SimpleCursorAdapter由於涉及到數據庫,所以打算單獨拿出來講。