《Android》『ListView』- 自訂一個繼承 BaseAdapter 的 Adapter 以實現客製化 ListView
《Android Developers 參考文獻》
《簡單介紹》
在了解 ListView 的靜態載入與動態載入的方式後,我們對於基本的 ListView 建構已經可以非常迅速地完成,但現在問題來了,若是我們想要有一個完全客製化的 ListView 時,該怎麼做呢?前面我們有提到,ListView 類別是負責將列表顯示在螢幕上,而 Adapter 類別負責處理資料內容與介面的連結,也因此,就像之前介紹過的 Spinner 元件一樣,若是想要有一個客製化的介面,我們必須從改寫 Adapter 來著手。
《自訂一個繼承 BaseAdapter 的 Adapter》
BaseAdapter 為一個用來實作 ListAdapter 和 SpinnerAdapter 介面的抽象類別,透過繼承 BaseAdapter,我們可以重新覆寫其中的幾個抽象方法,條列如下 –
public int getCount();
取得 ListView 列表 Item 的數量。通常數量就是從建構子傳入的陣列或是集合大小。
public Object getItem(int position);
取得 ListView 列表於 position 位置上的 Item。position 通常是資料在陣列或是集合上的位置。
public long getItemId(int position);
取得 ListView 列表於 position 位置上的 Item 的 ID,一般用 position 的值即可。
public View getView(int position, View convertView, ViewGroup parent);
通常會設定與回傳 convertView 作為顯示在這個 position 位置的 Item 的 View。
這樣講可能還是有點抽象,以下透過程式碼片段,直接實作一個繼承自 BaseAdapter 的 Adapter,並命名為 ListAdapter。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
package ... import ... public class ListAdapter extends BaseAdapter { private LayoutInflater mLayInf; List<Map<String, Object>> mItemList; public ListAdapter(Context context, List<Map<String, Object>> itemList) { mLayInf = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); mItemList = itemList; } @Override public int getCount() { //取得 ListView 列表 Item 的數量 return mItemList.size(); } @Override public Object getItem(int position) { //取得 ListView 列表於 position 位置上的 Item return position; } @Override public long getItemId(int position) { //取得 ListView 列表於 position 位置上的 Item 的 ID return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { //設定與回傳 convertView 作為顯示在這個 position 位置的 Item 的 View。 View v = mLayInf.inflate(R.layout.list_view_item, parent, false); ImageView imgView = (ImageView) v.findViewById(R.id.imgView); TextView txtView = (TextView) v.findViewById(R.id.txtView); imgView.setImageResource(Integer.valueOf(mItemList.get(position).get("Item icon").toString())); txtView.setText(mItemList.get(position).get("Item title").toString()); return v; } } |
ListAdapter.java
我們透過建構子傳入 ListView 的項目內容 mItemList,並且宣告一個名為 mLayInf 的 LayoutInflater,用以把 xml 表述的 layout 轉化為 View。
在 getView() 中,我們宣告了一個 View 物件來定義 ListView 中顯示在這個 position 的 Item 的 View,因此為了要讓 ListView 使用自訂的介面,我們將 list_view_item.xml 透過 LayoutInflater 指定給它,在此範例中,我們沒有特別針對傳入的 position 參數設定不同的介面,也因此,ListView 的 Item 介面會一致的變成 list_view_item.xml 的樣式,接著,我們再將 list_view_item.xml 中所宣告的不同元件(ImageView, TextView)定義好行為即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="10dp" > <ImageView android:id="@+id/imgView" android:layout_width="wrap_content" android:layout_height="match_parent" /> <TextView android:id="@+id/txtView" android:layout_width="match_parent" android:layout_height="match_parent" android:textSize="20sp" android:paddingLeft="10dp" /> </LinearLayout> |
list_view_item.xml
此 layout 中,每個 ListView 的 Item 皆包含了一個 ImageView 與 TextView,透過更詳細的設定 getView() 裡面的行為,我們還可以在每個 Item 中實現不同的動作。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
package ... import ... public class MainActivity extends Activity { private static final String ITEM_TITLE = "Item title"; private static final String ITEM_ICON = "Item icon"; private TextView mTxtR; private ListView lsv_main; private ListAdapter mListAdapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mTxtR = (TextView) findViewById(R.id.txtR); //宣告 ListView 元件 lsv_main = (ListView)findViewById(R.id.lsv_main); lsv_main.setOnItemClickListener(listViewOnItemClickListener); //定義 ListView 每個 Item 的資料 List<Map<String, Object>> itemList = new ArrayList<Map<String, Object>>(); String[] regionList = {"1", "2", "3", "4"}; TypedArray regionIconList = getResources().obtainTypedArray(R.array.region_icon_list); for (int i = 0; i < regionList.length; i++) { Map<String, Object> item = new HashMap<String, Object>(); item.put(ITEM_TITLE, regionList[i]); item.put(ITEM_ICON, regionIconList.getResourceId(i, 0)); itemList.add(item); } // ListView 中所需之資料參數可透過修改 Adapter 的建構子傳入 mListAdapter = new ListAdapter(MainActivity.this, itemList); //設定 ListView 的 Adapter lsv_main.setAdapter(mListAdapter); } //設定 Item 的 OnClick 事件 private AdapterView.OnItemClickListener listViewOnItemClickListener = new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { TextView txtItemTitle = (TextView) view.findViewById(R.id.txtView); mTxtR.setText(txtItemTitle.getText()); } }; . . . } |
MainActivity.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.example.listviewcustomsample.MainActivity" > <TextView android:id="@+id/txtR" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="123" android:textSize="20sp" /> <ListView android:id="@+id/lsv_main" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@android:color/white" android:focusable="false" /> </RelativeLayout> |
activity_main.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 |
<?xml version="1.0" encoding="utf-8"?> <resources> . . . <string-array name="region_icon_list"> <item >@drawable/list_view_region_asia</item> <item >@drawable/list_view_region_america</item> <item >@drawable/list_view_region_europe</item> <item >@drawable/list_view_region_oceania</item> </string-array> ... </resources> |
strings.xml
在將自訂的 ListAdapter 建構好以後,接下來就是將其透過 ListView.setAdapter(ListAdapter)的方式傳入所需的 ListView 即可。
臉書留言
一般留言