ListView常用方法總結
1、listview拖動變黑解決方法
在Android中,ListView是最常用的一個控件,在做UI設計的時候,很多人希望能夠改變一下它的背景,使他能夠符合整體的UI設計,改變背景背很簡單只需要準備一張圖片然後指定屬性 android:background="@drawable/bg",不過不要高興地太早,當你這麼做以後,發現背景是變了,但是當你拖動,或者點擊list空白位置的時候發現ListItem都變成黑色的了。
這個要從Listview的效果說起,默認的ListItem背景是透明的,而ListView的背景是固定不變的,所以在滾動條滾動的過程中如果實時地去將當前每個Item的顯示內容跟背景進行混合運算,android系統爲了優化這個過程用,就使用了一個叫做android:cacheColorHint的屬性,在黑色主題下默認的顏色值是#191919.
如果你只是換背景的顏色的話,可以直接指定android:cacheColorHint爲你所要的顏色,如果你是用圖片做背景的話,那也只要將android:cacheColorHint指定爲透明(#00000000)就可以了,當然爲了美化是要犧牲一些效率的。最後就不回出現上面所說的你不想要的結果了。
1.、listview在拖動的時候背景圖片消失變成黑色背景。等到拖動完畢我們自己的背景圖片才顯示出來。
2 、listview的上邊和下邊有黑色的陰影。
3、lsitview的每一項之間需要設置一個圖片做爲間隔。
針對以上問題 在listview的xml文件中設置一下語句。
問題1 有如下代碼結解決 android:scrollingCache="false"
問題2 用如下代碼解決:android:fadingEdge="none"
問題3 用如下代碼解決: android:divider="@drawable/list_driver" 其中 @drawable/list_driver 是一個圖片資源
2、自定義ListView行間的分割線
Android平臺中系統控件提供了靈活的自定義選項,所有基於ListView或者說AbsListView實現的widget控件均可以通過下面的方法設置行間距的分割線,分割線可以自定義顏色、或圖片。
在ListView中我們使用屬性 android:divider="#FF0000" 定義分隔符爲紅色,當然這裏值可以指向一個drawable圖片對象,如果使用了圖片可能高度大於系統默認的像素,可以自己設置高度比如6個像素 android:dividerHeight="6px" ,在Java中ListView也有相關方法可以設置。
屬性名稱 |
描述 |
android:choiceMode |
規定此ListView所使用的選擇模式。缺省狀態下,list沒有選擇模式。 屬性值必須設置爲下列常量之一: none,值爲0,表示無選擇模式; singleChoice,值爲1,表示最多可以有一項被選中; multipleChoice,值爲2,表示可以多項被選中。 可參看全局屬性資源符號choiceMode。 |
android:divider |
規定List項目之間用某個圖形或顏色來分隔。可以用"@[+] [package:]type:name"或者"?[package:][type:]name"(主題屬性)的形式來指向某個已有資源;也可以用"#rgb","#argb","#rrggbb"或者"#aarrggbb"的格式來表示某個顏色。 可參看全局屬性資源符號divider。 |
android:dividerHeight |
分隔符的高度。若沒有指明高度,則用此分隔符固有的高度。必須爲帶單位的浮點數,如"14.5sp"。可用的單位如px(pixel像素),dp(density-independent pixels 與密集度無關的像素), sp(scaled pixels based on preferred font size 基於字體大小的固定比例的像素), in (inches英寸), mm (millimeters毫米)。 可以用"@[package:]type:name "或者"?[package:][type:]name"(主題屬性)的格式來指向某個包含此類型值的資源。 可參看全局屬性資源符號dividerHeight。 |
android:entries |
引用一個將使用在此ListView裏的數組。若數組是固定的,使用此屬性將比在程序中寫入更爲簡單。 必須以"@[+][package:]type:name"或者 "?[package:][type:]name"的形式來指向某個資源。 可參看全局屬性資源符號entries。 |
android:footerDividersEnabled |
設成flase時,此ListView將不會在頁腳視圖前畫分隔符。此屬性缺省值爲true。 屬性值必須設置爲true或false。 可以用"@[package:]type:name "或者"?[package:][type:]name"(主題屬性)的格式來指向某個包含此類型值的資源。 可參看全局屬性資源符號footerDividersEnabled。 |
android:headerDividersEnabled |
設成flase時,此ListView將不會在頁眉視圖後畫分隔符。此屬性缺省值爲true。 屬性值必須設置爲true或false。 可以用"@[package:]type:name "或者"?[package:][type:]name"(主題屬性)的格式來指向某個包含此類型值的資源。 可參看全局屬性資源符號headerDividersEnabled。 |
3、listview中的常用佈局樣式
android.R.layout.simple_list_item_1 一行text
android.R.layout.simple_list_item_2 --裏面有兩個text,一個可以當做title,一個可以當做內容
- SimpleAdapter adapter = new SimpleAdapter(this, data1,android.R.layout.simple_list_item_2,
- new String[]{"num","value"}, new int[]{android.R.id.text1,android.R.id.text2});
- listView.setAdapter(new ArrayAdapter<String>(this,
- android.R.layout.simple_list_item_single_choice, data));
- listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE); //單選按鈕樣式也可以設置爲多選
- listView.setAdapter(new ArrayAdapter<String>(this,
- android.R.layout.simple_list_item_multiple_choice, data));
- listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);//多選按鈕樣式也可設置單選行爲
- android.R.layout.simple_list_item_checked, data));
- listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
listview的顯示需要三個元素:
1.ListVeiw 用來展示列表的View。
2.適配器 用來把數據映射到ListView上的中介。
3.數據 具體的將被映射的字符串,圖片,或者基本組件。
根據列表的適配器類型,列表分爲三種,ArrayAdapter,SimpleAdapter和SimpleCursorAdapter
一、ArrayAdapter的listview
- private ListView listView;
- @Override
- public void onCreate(Bundle savedInstanceState){
- super.onCreate(savedInstanceState);
- listView = new ListView(this);
- //android.R.layout.simple_list_item_1是系統定義好的佈局文件只顯示一行文字
- listView.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_expandable_list_item_1,getData()));
- setContentView(listView);
- }
- private List<String> getData(){
- List<String> data = new ArrayList<String>();
- data.add("測試數據1");
- data.add("測試數據2");
- data.add("測試數據3");
- data.add("測試數據4");
- return data;
- }
- }
二、CursorAdapter
通過遊標獲得數據後,在listview中顯示結果。
Cursor cursor = getContentResolver().query(People.CONTENT_URI, null, null, null, null);先獲得一個指向系統通訊錄數據庫的Cursor對象獲得數據來源。
startManagingCursor(cursor);我們將獲得的Cursor對象交由Activity管理,這樣Cursor的生命週期和Activity便能夠自動同步。
SimpleCursorAdapter 構造函數前面3個參數和ArrayAdapter是一樣的,最後兩個參數:一個包含數據庫的列的String型數組,一個包含佈局文件中對應組件id的int型數組。其作用是自動的將String型數組所表示的每一列數據映射到佈局文件對應id的組件上。下面的代碼,將NAME列的數據一次映射到佈局文件的id爲text1的組件上。
注意:需要在AndroidManifest.xml中如權限:<uses-permission android:name="android.permission.READ_CONTACTS"></uses-permission>
- <SPAN style="FONT-SIZE: 14px">public class MainActivity extends Activity {
- private ListView listView;
- @Override
- public void onCreate(Bundle savedInstanceState){
- super.onCreate(savedInstanceState);
- listView = new ListView(this);
- Cursor cursor = getContentResolver().query(People.CONTENT_URI, null,
- null, null, null);
- startManagingCursor(cursor);
- ListAdapter listAdapter = new SimpleCursorAdapter(this,
- android.R.layout.simple_expandable_list_item_1, cursor,
- new String[] { People.NAME }, new int[] { android.R.id.text1 });
- listView.setAdapter(listAdapter);
- setContentView(listView);
- }
- }</SPAN>
如果將simplecursoradapter改成這樣:
- android.R.layout.simple_expandable_list_item_2, cursor,
- new String[] { People.NAME, People.NAME }, new int[] { android.R.id.text1,android.R.id.text2 });
則會顯示android.R.layout.simple_expandable_list_item_2對應格式的list。
三、SimpleAdapter
SimpleAdapter可以自定義拓展listview。
使用simpleAdapter的數據用一般都是HashMap構成的List,list的每一節對應ListView的每一行。HashMap的每個鍵值數據映射到佈局文件中對應id的組件上。因爲系統沒有對應的佈局文件可用,我們可以自己定義一個佈局vlist.xml。下面做適配,new一個SimpleAdapter參數一次是:this,佈局文件,HashMap的
title 和 info,img。佈局文件的組件id,title,info,img。佈局文件的各組件分別映射到HashMap的各元素上,完成適配。
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="horizontal" android:layout_width="fill_parent"
- android:layout_height="fill_parent">
- <ImageView android:id="@+id/img"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_margin="5px"/>
- <LinearLayout android:orientation="vertical"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content">
- <TextView android:id="@+id/title"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textSize="22px" />
- <TextView android:id="@+id/info"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textSize="13px" />
- </LinearLayout>
- </LinearLayout>
- public class MainActivity extends ListActivity {
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- SimpleAdapter adapter = new SimpleAdapter(this, getData(),
- R.layout.activity_main,
- new String[] { "title", "info", "img" }, new int[] {
- R.id.title, R.id.info, R.id.img });
- setListAdapter(adapter);
- }
- private List<Map<String, Object>> getData() {
- List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
- Map<String, Object> map = new HashMap<String, Object>();
- map.put("title", "1");
- map.put("info", " 1 ");
- map.put("img", R.drawable.ic_launcher);
- list.add(map);
- map = new HashMap<String, Object>();
- map.put("title", "2");
- map.put("info", " 2 ");
- map.put("img", R.drawable.ic_launcher);
- list.add(map);
- map = new HashMap<String, Object>();
- map.put("title", "3");
- map.put("info", " 3 ");
- map.put("img", R.drawable.ic_launcher);
- list.add(map);
- return list;
- }
- }
*使用simpleadapter我們可以顯示許多自定義的複雜視圖,但是按鈕是無法在simpleadapter中使用的。
四、BaseAdapter
BaseAdapter是一個公共基類適配器,直接提供相關控件的數據提供。
- <SPAN style="FONT-SIZE: 14px"><?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"
- android:orientation="horizontal" >
- <ImageView
- android:id="@+id/img"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_margin="5px" />
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="vertical" >
- <TextView
- android:id="@+id/title"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textSize="22px" />
- <TextView
- android:id="@+id/info"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textSize="13px" />
- </LinearLayout>
- <Button
- android:id="@+id/view_btn"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="bottom|right"
- android:text="btn" />
- </LinearLayout></SPAN>
- <SPAN style="FONT-SIZE: 14px">public class MainActivity extends ListActivity {
- //通過一個list去映射數據顯示在listview中
- private List<Map<String, Object>> mData;
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- mData = getData();
- MyAdapter adapter = new MyAdapter(this);
- setListAdapter(adapter);
- }
- private List<Map<String, Object>> getData() {
- List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
- Map<String, Object> map = new HashMap<String, Object>();
- map.put("title", "1");
- map.put("info", " 1 ");
- map.put("img", R.drawable.ic_launcher);
- list.add(map);
- map = new HashMap<String, Object>();
- map.put("title", "2");
- map.put("info", " 2 ");
- map.put("img", R.drawable.ic_launcher);
- list.add(map);
- map = new HashMap<String, Object>();
- map.put("title", "3");
- map.put("info", " 3 ");
- map.put("img", R.drawable.ic_launcher);
- list.add(map);
- return list;
- }
- // ListView 中某項被選中後的邏輯
- @Override
- protected void onListItemClick(ListView l, View v, int position, long id) {
- Log.v("MyListView4-click", (String) mData.get(position).get("title"));
- }
- /**
- * listview中點擊按鍵彈出對話框
- */
- public void showInfo() {
- new AlertDialog.Builder(this).setTitle("Btn listview")
- .setMessage("123")
- .setPositiveButton("確定", new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- }
- }).show();
- }
- public final class ViewHolder {
- public ImageView img;
- public TextView title;
- public TextView info;
- public Button viewBtn;
- }
- public class MyAdapter extends BaseAdapter {
- private LayoutInflater mInflater;
- public MyAdapter(Context context) {
- this.mInflater = LayoutInflater.from(context);
- }
- public int getCount() {
- // TODO Auto-generated method stub
- return mData.size();
- }
- public Object getItem(int arg0) {
- // TODO Auto-generated method stub
- return null;
- }
- public long getItemId(int arg0) {
- // TODO Auto-generated method stub
- return 0;
- }
- public View getView(int position, View convertView, ViewGroup parent) {
- ViewHolder holder = null;
- if (convertView == null) {
- holder = new ViewHolder();
- convertView = mInflater.inflate(R.layout.activity_main, null);
- holder.img = (ImageView) convertView.findViewById(R.id.img);
- holder.title = (TextView) convertView.findViewById(R.id.title);
- holder.info = (TextView) convertView.findViewById(R.id.info);
- holder.viewBtn = (Button) convertView
- .findViewById(R.id.view_btn);
- convertView.setTag(holder);
- } else {
- holder = (ViewHolder) convertView.getTag();
- }
- holder.img.setBackgroundResource((Integer) mData.get(position).get(
- "img"));
- holder.title.setText((String) mData.get(position).get("title"));
- holder.info.setText((String) mData.get(position).get("info"));
- holder.viewBtn.setOnClickListener(new View.OnClickListener() {
- public void onClick(View v) {
- showInfo();
- }
- });
- return convertView;
- }
- }
- }</SPAN>
下面將對上述代碼,做詳細的解釋,listView在開始繪製的時候,系統首先調用getCount()函數,根據他的返回值得到listView的長度(這也是爲什麼在開始的第一張圖特別的標出列表長度),然後根據這個長度,調用getView()逐一繪製每一行。如果你的getCount()返回值是0的話,列表將不顯示同樣return 1,就只顯示一行。
系統顯示列表時,首先實例化一個適配器(這裏將實例化自定義的適配器)。當手動完成適配時,必須手動映射數據,這需要重寫getView()方法。系統在繪製列表的每一行的時候將調用此方法。getView()有三個參數,position表示將顯示的是第幾行,covertView是從佈局文件中inflate來的佈局。我們用LayoutInflater的方法將定義好的vlist2.xml文件提取成View實例用來顯示。然後將xml文件中的各個組件實例化(簡單的findViewById()方法)。這樣便可以將數據對應到各個組件上了。但是按鈕爲了響應點擊事件,需要爲它添加點擊監聽器,這樣就能捕獲點擊事件。至此一個自定義的listView就完成了,現在讓我們回過頭從新審視這個過程。系統要繪製ListView了,他首先獲得要繪製的這個列表的長度,然後開始繪製第一行,怎麼繪製呢?調用getView()函數。在這個函數裏面首先獲得一個View(實際上是一個ViewGroup),然後再實例並設置各個組件,顯示之。好了,繪製完這一行了。那 再繪製下一行,直到繪完爲止。在實際的運行過程中會發現listView的每一行沒有焦點了,這是因爲Button搶奪了listView的焦點,只要佈局文件中將Button設置爲沒有焦點就OK了。
運行效果如圖
五、本次要講的是一個listview的進階效果,主要實現的功能是,單擊顯示的item時,會顯示出一個大圖,以突出效果,即抽屜效果的ListView。效果如下所示:
其主要實現思路是:在getView的時候,動態修改佈局,將選中的item添加新的View,這樣就做到了點擊的時候,與其他的item不同的效果。
代碼如下:
- public class MainActivity extends ListActivity {
- DrawListAdapter adapter;
- int[] imgs={R.drawable.image,R.drawable.packed,R.drawable.paste,R.drawable.text,R.drawable.delete};
- String[] text={"第一抽屜","第二抽屜","第三抽屜","第四抽屜","第五抽屜"};
- int currentItem=0;
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- adapter = new DrawListAdapter(this);
- //setListAdapter和getListView方法是ListActivity的方法,分別用於設置adapter和獲得一個listview
- this.setListAdapter(adapter);
- this.getListView().setOnItemClickListener(new OnItemClickListener(){
- public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
- long arg3) {
- // TODO Auto-generated method stub
- currentItem=arg2;
- //notifyDataSetChanged()可以在修改適配器綁定的數組後,不用重新刷新Activity,通知Activity更新ListView
- adapter.notifyDataSetChanged();
- }
- });
- }
- public class DrawListAdapter extends BaseAdapter{
- Activity activity;
- LayoutInflater inflater;
- public DrawListAdapter(Activity a){
- activity=a;
- inflater=activity.getLayoutInflater();
- }
- public int getCount() {
- // TODO Auto-generated method stub
- return imgs.length;
- }
- public Object getItem(int arg0) {
- // TODO Auto-generated method stub
- return null;
- }
- public long getItemId(int position) {
- // TODO Auto-generated method stub
- return position;
- }
- public View getView(int position, View convertView, ViewGroup arg2) {
- // TODO Auto-generated method stub
- LinearLayout layout=new LinearLayout(activity);
- layout.setOrientation(LinearLayout.VERTICAL);
- layout.addView(addTitleView(position));
- if(currentItem==position){
- layout.addView(addCustomView(position));
- }
- return layout;
- }
- //獲取選中項的內容
- private View addCustomView(int i) {
- // TODO Auto-generated method stub
- View view=new View(activity);
- ImageView iv=new ImageView(activity);
- //根據點擊的position設置相應要顯示的圖片
- switch (i) {
- case 0:
- iv.setImageResource(R.drawable.ic_launcher);
- view=iv;
- break;
- case 1:
- iv.setImageResource(R.drawable.ic_launcher);
- view=iv;
- break;
- case 2:
- iv.setImageResource(R.drawable.ic_launcher);
- view=iv;
- break;
- case 3:
- iv.setImageResource(R.drawable.ic_launcher);
- view=iv;
- break;
- case 4:
- iv.setImageResource(R.drawable.ic_launcher);
- view=iv;
- break;
- }
- return view;
- }
- //獲取list的標題內容
- private View addTitleView(int i) {
- // TODO Auto-generated method stub
- LinearLayout layout=new LinearLayout(activity);
- layout.setOrientation(LinearLayout.HORIZONTAL);
- ImageView iv=new ImageView(activity);
- iv.setImageResource(imgs[i]);
- layout.addView(iv,new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,LinearLayout.LayoutParams.WRAP_CONTENT));
- TextView tv=new TextView(activity);
- tv.setText(text[i]);
- layout.addView(tv,new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,LinearLayout.LayoutParams.WRAP_CONTENT));
- layout.setGravity(Gravity.CENTER);
- return layout;
- }
- }
- }