Android listview与adapter用法
2019獨角獸企業(yè)重金招聘Python工程師標準>>>
一個ListView通常有兩個職責(zé)。
(1)將數(shù)據(jù)填充到布局。
(2)處理用戶的選擇點擊等操作。
第一點很好理解,ListView就是實現(xiàn)這個功能的。第二點也不難做到,在后面的學(xué)習(xí)中讀者會發(fā)現(xiàn),這非常簡單。
一個ListView的創(chuàng)建需要3個元素。
(1)ListView中的每一列的View。
(2)填入View的數(shù)據(jù)或者圖片等。
(3)連接數(shù)據(jù)與ListView的適配器。
也就是說,要使用ListView,首先要了解什么是適配器。適配器是一個連接數(shù)據(jù)和AdapterView(ListView就是一個典型的AdapterView,后面還會學(xué)習(xí)其他的)的橋梁,通過它能有效地實現(xiàn)數(shù)據(jù)與AdapterView的分離設(shè)置,使AdapterView與數(shù)據(jù)的綁定更加簡便,修改更加方便
Android中提供了很多的Adapter,表4-5列出了常用的幾個。
其實適配器還有很多,要注意的是,各種Adapter只不過是轉(zhuǎn)換的方式和能力不一樣而已。下面就通過使用不同的Adapter來為ListView綁定數(shù)據(jù)(SimpleCursorAdapter暫且不講,后面講SQLite時會介紹)。
4.12.1 ListView使用ArrayAdapter
用ArrayAdapter可以實現(xiàn)簡單的ListView的數(shù)據(jù)綁定。默認情況下,ArrayAdapter綁定每個對象的toString值到layout中預(yù)先定義的TextView控件上。ArrayAdapter的使用非常簡單。 實例: 工程目錄:EX_04_12 在布局文件中加入一個ListView控件。
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="fill_parent" android:layout_height="fill_parent"><!-- 添加一個ListView控件 --> <ListView android:id="@+id/lv" android:layout_width="fill_parent" android:layout_height="fill_parent"/> </LinearLayout>然后在Activity中初始化。
public class MyListView extends Activity {private static final String[] strs = new String[] {"first", "second", "third", "fourth", "fifth"};//定義一個String數(shù)組用來顯示ListView的內(nèi)容private ListView lv;/** Called when the activity is first created. */@Override public void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.main);lv = (ListView) findViewById(R.id.lv);//得到ListView對象的引用 /*為ListView設(shè)置Adapter來綁定數(shù)據(jù)*/ lv.setAdapter(new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1, strs));} }圖4-29 ListView使用ArrayAdapter運行效果 代碼非常的簡單,運行效果如圖4-29所示。
分析一下使用的步驟。 (1)定義一個數(shù)組來存放ListView中item的內(nèi)容。 (2)通過實現(xiàn)ArrayAdapter的構(gòu)造函數(shù)來創(chuàng)建一個ArrayAdapter的對象。 (3)通過ListView的setAdapter()方法綁定ArrayAdapter。 其中第二步有必要說一下的是,ArrayAdapter有多個構(gòu)造函數(shù),例子中實現(xiàn)的是最常用的一種。第一個參數(shù)為上下文,第二個參數(shù)為一個包含TextView,用來填充ListView的每一行的布局資源ID。第三個參數(shù)為ListView的內(nèi)容。其中第二個參數(shù)可以自定義一個layout,但是這個layout必須要有TextView控件。通常我們使用Android提供的資源,除了例子中所用的,常用的還有如下幾種,可實現(xiàn)帶RadioButton和CheckBox的ListView。 (1)通過指定android.R.layout.simple_list_item_checked這個資源,實現(xiàn)帶選擇框的ListView。需要用setChoiceMode()方法設(shè)定選擇為多選還是單選,否則將不能實現(xiàn)選擇效果,運行效果如圖4-30所示。 實現(xiàn)代碼如下:
lv.setAdapter(new ArrayAdapter<String>(this,android.R.layout.simple_list_item_checked, strs)); lv.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);(2)通過指定android.R.layout.simple_list_item_multiple_choice這個資源實現(xiàn)帶CheckBox的ListView。同樣的,需要用setChoiceMode()方法來設(shè)置單選或者多選,運行效果如圖4-31所示。 實現(xiàn)代碼如下:
lv.setAdapter(new ArrayAdapter<String>(this,android.R.layout.simple_list_item_multiple_choice, strs)); lv.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);(3)通過指定android.R.layout.simple_list_item_single_choice這個資源實現(xiàn)帶RadioButton的ListView。這里要注意的是,這里并不是指定了單選。是多選還是單選要通過setChoiceMode()方法來指定,運行效果如圖4-32所示。 實現(xiàn)代碼如下:
lv.setAdapter(newArrayAdapter<String>(this,android.R.layout.simple_list_item_single_choice,strs));lv.setChoiceMode(ListView.CHOICE_MODE_SINGLE);▲圖4-30 帶選擇框的ListView
▲圖4-31 帶CheckBox的ListView
▲圖4-32 帶RadioButton的ListView
在前面講到過,ListView的職責(zé)除了填充數(shù)據(jù)外,還要處理用戶的操作。通過如下的代碼就可以為ListView綁定一個點擊監(jiān)聽器,點擊后在標題欄顯示點擊的行數(shù)。
lv.setOnItemClickListener(new OnItemClickListener() {@Overridepublicvoid onItemClick(AdapterView<?> arg0, View arg1, int arg2,long arg3) {//點擊后在標題上顯示點擊了第幾行 setTitle("你點擊了第"+arg2+"行");}});4.12.2 ListView使用SimpleAdapter
很多時候需要在列表中展示一些除了文字以外的東西,比如圖片等。這時候可以使用SimpleAdapter。SimpleAdapter的使用也非常簡單,同時它的功能也非常強大。可以通過它自定義ListView中的item的內(nèi)容,比如圖片、多選框等。看一個例子,實現(xiàn)一個每一行都有一個ImageView和TextView的ListView。先看一下運行效果,如圖4-34所示。
▲圖4-34 帶圖標的ListView
首先在布局文件中增加一個ListView控件。 還需要定義一個ListView中每一行的布局,用RelativeLayout來實現(xiàn)一個帶兩行字和一個圖片的布局。
item.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="fill_parent"android:layout_height="fill_parent"><ImageViewandroid:id="@+id/ItemImage"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignParentRight="true" /><TextViewandroid:id="@+id/ItemTitle"android:layout_width="fill_parent"android:layout_height="wrap_content"android:textSize="20sp" /><TextViewandroid:id="@+id/ItemText"android:layout_width="fill_parent"android:layout_height="wrap_content"android:layout_below="@+id/ItemTitle" /> </RelativeLayout>配置完畢,就可以在Java代碼中為ListView綁定數(shù)據(jù)。
public class MainActivity extends AppCompatActivity {private static final String[] strs = new String[]{"first", "second", "third", "fourth", "fifth"};//定義一個String數(shù)組用來顯示ListView的內(nèi)容private ListView lv;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);lv = (ListView) findViewById(R.id.lv);/*定義一個動態(tài)數(shù)組*/ArrayList<HashMap<String, Object>> listItem = new ArrayList<HashMap<String, Object>>();/*在數(shù)組中存放數(shù)據(jù)*/for(int i=0;i<10;i++){HashMap<String, Object> map = new HashMap<String, Object>();map.put("ItemImage", R.drawable.icon);//加入圖片map.put("ItemTitle", "第"+i+"行");map.put("ItemText", "這是第"+i+"行");listItem.add(map);}SimpleAdapter mSimpleAdapter = new SimpleAdapter(this,listItem,//需要綁定的數(shù)據(jù)R.layout.item,//每一行的布局new String[] {"ItemImage","ItemTitle", "ItemText"},//動態(tài)數(shù)組中的數(shù)據(jù)源的鍵對應(yīng)到定義布局的View中new int[] {R.id.ItemImage,R.id.ItemTitle,R.id.ItemText});lv.setAdapter(mSimpleAdapter);//為ListView綁定適配器lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {@Overridepublic void onItemClick(AdapterView<?> arg0, View arg1, int arg2,long arg3) {setTitle("你點擊了第"+arg2+"行");//設(shè)置標題欄顯示點擊的行}});} }使用simpleAdapter的數(shù)據(jù)一般都是用HashMap構(gòu)成的列表,列表的每一節(jié)對應(yīng)ListView的每一行。通過SimpleAdapter的構(gòu)造函數(shù),將HashMap的每個鍵的數(shù)據(jù)映射到布局文件中對應(yīng)控件上。這個布局文件一般根據(jù)自己的需要來自己定義。梳理一下使用SimpleAdapter的步驟。 (1)根據(jù)需要定義ListView每行所實現(xiàn)的布局。 (2)定義一個HashMap構(gòu)成的列表,將數(shù)據(jù)以鍵值對的方式存放在里面。 (3)構(gòu)造SimpleAdapter對象。 (4)將LsitView綁定到SimpleAdapter上。
4.12.3 ListView使用BaseAdapter與ListView的優(yōu)化
在ListView的使用中,有時候還需要在里面加入按鈕等控件,實現(xiàn)單獨的操作。也就是說,這個ListView不再只是展示數(shù)據(jù),也不僅僅是這一行要來處理用戶的操作,而是里面的控件要獲得用戶的焦點。讀者可以試試用SimpleAdapter添加一個按鈕到ListView的條目中,會發(fā)現(xiàn)可以添加,但是卻無法獲得焦點,點擊操作被ListView的Item所覆蓋。這時候最方便的方法就是使用靈活的適配器BaseAdapter了。
▲圖4-35 BaseAdapter中的方法
使用BaseAdapter必須寫一個類繼承它,同時BaseAdapter是一個抽象類,繼承它必須實現(xiàn)它的方法。BaseAdapter的靈活性就在于它要重寫很多方法,看一下有哪些方法,如圖4-35所示為繼承自BaseAdapter的SpeechListAdapter所實現(xiàn)的方法,其中最重要的即為getView()方法。這些方法都有什么作用呢?我們通過分析ListView的原理來為讀者解答。
當(dāng)系統(tǒng)開始繪制ListView的時候,首先調(diào)用getCount()方法。得到它的返回值,即ListView的長度。然后系統(tǒng)調(diào)用getView()方法,根據(jù)這個長度逐一繪制ListView的每一行。也就是說,如果讓getCount()返回1,那么只顯示一行。而getItem()和getItemId()則在需要處理和取得Adapter中的數(shù)據(jù)時調(diào)用。那么getView如何使用呢?如果有10000行數(shù)據(jù),就繪制10000次?這肯定會極大的消耗資源,導(dǎo)致ListView滑動非常的慢,那應(yīng)該怎么做呢?通過一個例子來講解如何在使用BaseAdapter的時候優(yōu)化ListView的顯示。例子中將上一節(jié)中的ImageView換成Button,并且處理Button的點擊事件,其中對ListView的顯示做了優(yōu)化。
布局文件和上一例類同,讀者可以在光盤的工程目錄中查看,這里只給出Activity類。
public class MainActivity extends AppCompatActivity {private ListView lv;/*定義一個動態(tài)數(shù)組*/ArrayList<HashMap<String, Object>> listItem;/*** Called when the activity is first created.*/@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);lv = (ListView) findViewById(R.id.lv);MyAdapter mAdapter = new MyAdapter(this);//得到一個MyAdapter對象lv.setAdapter(mAdapter);//為ListView綁定Adapter/*為ListView添加點擊事件*/lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {@Overridepublic void onItemClick(AdapterView<?> arg0, View arg1, int arg2,long arg3) {Log.v("MyListViewBase", "你點擊了ListView條目" + arg2);//在LogCat中輸出信息}});}/*添加一個得到數(shù)據(jù)的方法,方便使用*/private ArrayList<HashMap<String, Object>> getDate() {ArrayList<HashMap<String, Object>> listItem = new ArrayList<HashMap<String, Object>>();/*為動態(tài)數(shù)組添加數(shù)據(jù)*/for (int i = 0; i < 30; i++) {HashMap<String, Object> map = new HashMap<String, Object>();map.put("ItemTitle", "第" + i + "行");map.put("ItemText", "這是第" + i + "行");listItem.add(map);}return listItem;}/*新建一個類繼承BaseAdapter,實現(xiàn)視圖與數(shù)據(jù)的綁定*/private class MyAdapter extends BaseAdapter {private LayoutInflater mInflater;//得到一個LayoutInfalter對象用來導(dǎo)入布局 /*構(gòu)造函數(shù)*/public MyAdapter(Context context) {this.mInflater = LayoutInflater.from(context);}@Overridepublic int getCount() {return getDate().size();//返回數(shù)組的長度}@Overridepublic Object getItem(int position) {return null;}@Overridepublic long getItemId(int position) {return 0;}/*書中詳細解釋該方法*/@Overridepublic View getView(final int position, View convertView, ViewGroup parent) {ViewHolder holder;//觀察convertView隨ListView滾動情況Log.v("MyListViewBase", "getView " + position + " " + convertView);if (convertView == null) {convertView = mInflater.inflate(R.layout.item,null);holder = new ViewHolder();/*得到各個控件的對象*/holder.title = (TextView) convertView.findViewById(R.id.ItemTitle);holder.text = (TextView) convertView.findViewById(R.id.ItemText);holder.bt = (Button) convertView.findViewById(R.id.ItemButton);convertView.setTag(holder);//綁定ViewHolder對象} else {holder = (ViewHolder) convertView.getTag();//取出ViewHolder對象}/*設(shè)置TextView顯示的內(nèi)容,即我們存放在動態(tài)數(shù)組中的數(shù)據(jù)*/holder.title.setText(getDate().get(position).get("ItemTitle").toString());holder.text.setText(getDate().get(position).get("ItemText").toString());/*為Button添加點擊事件*/holder.bt.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Log.v("MyListViewBase", "你點擊了按鈕" + position); //打印Button的點擊信息}});return convertView;}}/*存放控件*/public final class ViewHolder {public TextView title;public TextView text;public Button bt;} }item.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="fill_parent"android:layout_height="fill_parent"><Buttonandroid:id="@+id/ItemButton"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="點我"android:focusable="false"android:layout_alignParentRight="true" /><TextViewandroid:id="@+id/ItemTitle"android:layout_width="fill_parent"android:layout_height="wrap_content"android:textSize="20sp" /><TextViewandroid:id="@+id/ItemText"android:layout_width="fill_parent"android:layout_height="wrap_content"android:layout_below="@+id/ItemTitle" /> </RelativeLayout>運行效果如圖4-36所示。還需要注意的是,Button會搶奪ListView的焦點,需要將Button設(shè)置為沒有焦點。設(shè)置非常簡單,只需要在xml的Button標簽下加入一行:android:focusable=“false”代碼就可以了。在LogCat觀察點擊后輸出的信息,如圖4-37所示。
▲圖4-36 使用BaseAdapter的ListVie
▲圖4-37 點擊ListView條目和Button得到的輸出
代碼中g(shù)etView()方法不容易理解。其實完全可以不用所謂的convertView和ViewHolder,直接導(dǎo)入布局并且設(shè)置控件顯示的內(nèi)容就可以了。但是這意味著有多少行數(shù)據(jù)就需要繪制多少行ListView,這顯然是不可取的。這里采用了一種優(yōu)化的方法。代碼中,在getView()方法中加入了一行l(wèi)og輸出convertView的內(nèi)容。滾動ListView,輸出信息如圖4-38所示。 從圖4-38中可以看出,當(dāng)啟動Activity呈現(xiàn)第一屏ListView的時候,convertView為零。當(dāng)用戶向下滾動ListView時,上面的條目變?yōu)椴豢梢?#xff0c;下面出現(xiàn)新的條目。這時候convertView不再為空,而是創(chuàng)建了一系列的convertView的值。當(dāng)又往下滾一屏的時候,發(fā)現(xiàn)第11行的容器用來容納第22行,第12行的容器用來容納第23行。也就是說convertView相當(dāng)于一個緩存,開始為0,當(dāng)有條目變?yōu)椴豢梢?#xff0c;它緩存了它的數(shù)據(jù),后面再出來的條目只需要更新數(shù)據(jù)就可以了,這樣大大節(jié)省了系統(tǒng)資料的開銷。 還可以繼續(xù)優(yōu)化。雖然重復(fù)利用了已經(jīng)繪制的view,但是要得到其中的控件,需要在控件的容器中通過findViewById的方法來獲得。如果這個容器非常復(fù)雜,這顯然會增加系統(tǒng)資源的開銷。在上面的例子中,引入了Tag的概念。或許不是最好的辦法,但是它確實能使ListView變得更流暢。代碼中,當(dāng)convertView為空時,用setTag()方法為每個View綁定一個存放控件的ViewHolder對象。當(dāng)convertView不為空,重復(fù)利用已經(jīng)創(chuàng)建的view的時候,使用getTag()方法獲取綁定的ViewHolder對象,這樣就避免了findViewById對控件的層層查詢,而是快速定位到控件。
轉(zhuǎn)載于:https://my.oschina.net/yongqingfan/blog/760066
總結(jié)
以上是生活随笔為你收集整理的Android listview与adapter用法的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python中单引号,双引号,多引号区别
- 下一篇: Android图表和图形创建库:Eaze