Android 實現listview中checkbox的多選與記錄

在很多時候,我們會用到listview和checkbox配合來提供給用戶一些選擇操作。比如在一個清單頁面,我們需要記錄用戶勾選了哪些條目。這個的實現並不太難,但是有很多朋友來問我如何實現,他們有遇到各種各樣的問題,這裏就一併寫出來和大家一起分享。ListView的操作就一定會涉及到item和Adapter,我們還是先來實現這部分內容。首先,寫個item的xml佈局,裏面放置一個TextView和一個CheckBox。要注意的時候,這裏我設置了CheckBox沒有焦點,這樣的話,無法單獨點擊checkbox,而是在點擊listview的條目後,Checkbox會響應操作。

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3.     android:layout_width="fill_parent"
  4.     android:layout_height="fill_parent"
  5.     android:orientation="horizontal" >
  6.     <TextView
  7.         android:id="@+id/item_tv"
  8.         android:layout_width="0dp"
  9.         android:layout_height="wrap_content"
  10.         android:layout_weight="1"
  11.         android:gravity="center_vertical"
  12.          />
  13.     <CheckBox
  14.         android:id="@+id/item_cb"
  15.         android:layout_width="wrap_content"
  16.         android:layout_height="wrap_content"
  17.         android:clickable="false"
  18.         android:focusable="false"
  19.         android:focusableInTouchMode="false" 
  20.         android:gravity="center_vertical"
  21.         />
  22. </LinearLayout>
複製代碼
下面就寫一個Adapter類,我們依然繼承BaseAdapter類。這裏我們使用一個HashMap<Integer,boolean>的鍵值來記錄checkbox在對應位置的選中狀況,這是本例的實現的基礎。

  1. package com.notice.listcheck;
  2. import java.util.ArrayList;
  3. import java.util.HashMap;
  4. import android.content.Context;
  5. import android.view.LayoutInflater;
  6. import android.view.View;
  7. import android.view.ViewGroup;
  8. import android.widget.BaseAdapter;
  9. import android.widget.CheckBox;
  10. import android.widget.TextView;
  11. public class MyAdapter extends BaseAdapter{
  12.     // 填充數據的list
  13.     private ArrayList<String> list;
  14.     // 用來控制CheckBox的選中狀況
  15.     private static HashMap<Integer,Boolean> isSelected;
  16.     // 上下文
  17.     private Context context;
  18.     // 用來導入佈局
  19.     private LayoutInflater inflater = null;
  20.     
  21.     // 構造器
  22.     public MyAdapter(ArrayList<String> list, Context context) {
  23.         this.context = context;
  24.         this.list = list;
  25.         inflater = LayoutInflater.from(context);
  26.         isSelected = new HashMap<Integer, Boolean>();
  27.         // 初始化數據
  28.         initDate();
  29.     }
  30.     // 初始化isSelected的數據
  31.     private void initDate(){
  32.         for(int i=0; i<list.size();i++) {
  33.             getIsSelected().put(i,false);
  34.         }
  35.     }
  36.     @Override
  37.     public int getCount() {
  38.         return list.size();
  39.     }
  40.     @Override
  41.     public Object getItem(int position) {
  42.         return list.get(position);
  43.     }
  44.     @Override
  45.     public long getItemId(int position) {
  46.         return position;
  47.     }
  48.     @Override
  49.     public View getView(int position, View convertView, ViewGroup parent) {
  50.         ViewHolder holder = null;
  51.             if (convertView == null) {
  52.             // 獲得ViewHolder對象
  53.             holder = new ViewHolder();
  54.             // 導入佈局並賦值給convertview
  55.             convertView = inflater.inflate(R.layout.listviewitem, null);
  56.             holder.tv = (TextView) convertView.findViewById(R.id.item_tv);
  57.             holder.cb = (CheckBox) convertView.findViewById(R.id.item_cb);
  58.             // 爲view設置標籤
  59.             convertView.setTag(holder);
  60.         } else {
  61.             // 取出holder
  62.             holder = (ViewHolder) convertView.getTag();
  63.             }

  64.         // 設置list中TextView的顯示
  65.         holder.tv.setText(list.get(position));
  66.         // 根據isSelected來設置checkbox的選中狀況
  67.         holder.cb.setChecked(getIsSelected().get(position));
  68.         return convertView;
  69.     }
  70.     public static HashMap<Integer,Boolean> getIsSelected() {
  71.         return isSelected;
  72.     }
  73.     public static void setIsSelected(HashMap<Integer,Boolean> isSelected) {
  74.         MyAdapter.isSelected = isSelected;
  75.     }
  76. }
複製代碼
註釋已經寫的非常詳盡了,通過

  1. holder.cb.setChecked(getIsSelected().get(position));
複製代碼
這行代碼我們實現了設置CheckBox的選中狀況。

那麼我們只需要在點擊事件中,控制isSelected的鍵值即可控制對應位置checkbox的選中了。
在Activity中我們除了放置一個ListView外,還放置了三個按鈕,分別實現全選,取消和反選。

看下Activity類的代碼:

  1. package com.notice.listcheck;
  2. import java.util.ArrayList;
  3. import android.app.Activity;
  4. import android.os.Bundle;
  5. import android.view.View;
  6. import android.view.View.OnClickListener;
  7. import android.widget.AdapterView;
  8. import android.widget.AdapterView.OnItemClickListener;
  9. import android.widget.Button;
  10. import android.widget.ListView;
  11. import android.widget.TextView;
  12. public class Ex_checkboxActivity extends Activity {
  13.     
  14.     private ListView lv;
  15.     private MyAdapter mAdapter;
  16.     private ArrayList<String> list;
  17.     private Button bt_selectall;
  18.     private Button bt_cancel;
  19.     private Button bt_deselectall;
  20.     private int checkNum; // 記錄選中的條目數量
  21.     private TextView tv_show;// 用於顯示選中的條目數量
  22.     
  23.     /** Called when the activity is first created. */
  24.     @Override
  25.     public void onCreate(Bundle savedInstanceState) {
  26.         super.onCreate(savedInstanceState);
  27.         setContentView(R.layout.main);
  28.         /* 實例化各個控件 */
  29.         lv = (ListView) findViewById(R.id.lv);
  30.         bt_selectall = (Button) findViewById(R.id.bt_selectall);
  31.         bt_cancel = (Button) findViewById(R.id.bt_cancelselectall);
  32.         bt_deselectall = (Button) findViewById(R.id.bt_deselectall);
  33.         tv_show = (TextView) findViewById(R.id.tv);
  34.         list = new ArrayList<String>();
  35.         // 爲Adapter準備數據
  36.         initDate();
  37.         // 實例化自定義的MyAdapter
  38.         mAdapter = new MyAdapter(list, this);
  39.         // 綁定Adapter
  40.         lv.setAdapter(mAdapter);
  41.         // 全選按鈕的回調接口
  42.         bt_selectall.setOnClickListener(new OnClickListener() {
  43.             @Override
  44.             public void onClick(View v) {
  45.                 // 遍歷list的長度,將MyAdapter中的map值全部設爲true
  46.                 for (int i = 0; i < list.size(); i++) {
  47.                     MyAdapter.getIsSelected().put(i, true);
  48.                 }
  49.                 // 數量設爲list的長度
  50.                 checkNum = list.size();
  51.                 // 刷新listview和TextView的顯示
  52.                 dataChanged();
  53.             }
  54.         });
  55.         // 取消按鈕的回調接口
  56.         bt_cancel.setOnClickListener(new OnClickListener() {
  57.             @Override
  58.             public void onClick(View v) {
  59.                 // 遍歷list的長度,將已選的按鈕設爲未選
  60.                 for (int i = 0; i < list.size(); i++) {
  61.                     if (MyAdapter.getIsSelected().get(i)) {
  62.                         MyAdapter.getIsSelected().put(i, false);
  63.                         checkNum--;// 數量減1
  64.                     }
  65.                 }
  66.                 // 刷新listview和TextView的顯示
  67.                 dataChanged();
  68.             }
  69.         });
  70.         // 反選按鈕的回調接口
  71.         bt_deselectall.setOnClickListener(new OnClickListener() {
  72.             @Override
  73.             public void onClick(View v) {
  74.                 // 遍歷list的長度,將已選的設爲未選,未選的設爲已選
  75.                 for (int i = 0; i < list.size(); i++) {
  76.                     if (MyAdapter.getIsSelected().get(i)) {
  77.                         MyAdapter.getIsSelected().put(i, false);
  78.                         checkNum--;
  79.                     } else {
  80.                         MyAdapter.getIsSelected().put(i, true);
  81.                         checkNum++;
  82.                     }
  83.                 }
  84.                 // 刷新listview和TextView的顯示
  85.                 dataChanged();
  86.             }
  87.         });
  88.         
  89.         // 綁定listView的監聽器
  90.         lv.setOnItemClickListener(new OnItemClickListener() {
  91.             @Override
  92.             public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
  93.                     long arg3) {
  94.                 // 取得ViewHolder對象,這樣就省去了通過層層的findViewById去實例化我們需要的cb實例的步驟          ViewHolder holder = (ViewHolder) arg1.getTag();                // 改變CheckBox的狀態
  95.                 holder.cb.toggle();
  96.                 // 將CheckBox的選中狀況記錄下來
  97.                 MyAdapter.getIsSelected().put(arg2, holder.cb.isChecked()); 
  98.                 // 調整選定條目
  99.                 if (holder.cb.isChecked() == true) {
  100.                     checkNum++;
  101.                 } else {
  102.                     checkNum--;
  103.                 }
  104.                 // 用TextView顯示
  105.                 tv_show.setText("已選中"+checkNum+"項");
  106.                 
  107.             }
  108.         });
  109.     }
  110.     // 初始化數據
  111.     private void initDate() {
  112.         for (int i = 0; i < 15; i++) {
  113.             list.add("data" + "   " + i);
  114.         }
  115.     }
  116.     // 刷新listview和TextView的顯示
  117.     private void dataChanged() {
  118.         // 通知listView刷新
  119.         mAdapter.notifyDataSetChanged();
  120.         // TextView顯示最新的選中數目
  121.         tv_show.setText("已選中" + checkNum + "項");
  122.     }
  123.     
  124. }
複製代碼
代碼中在item的點擊事件中,直接調用

  1. holder.cb.toggle();
複製代碼
先改變CheckBox的狀態,然後將值存進map記錄下來

  1. MyAdapter.getIsSelected().put(arg2, holder.cb.isChecked());
複製代碼
而其他幾個Button的點擊事件,都是通過遍歷list的長度來設置isSelected的值,進而通知listview根據已經變化的adapter刷新,來實現Checkbox的對應選中狀態。因爲對listview的處理中我們仍然使用了ViewHolder來優化ListView的效率(通過findViewById層層查找是比較耗時的.

最後,來看下運行效果:
   



好了,就寫到這裏。相信大家都能明白了。這裏要說下一個問題,有很多朋友留言或者發郵件要博客中的一些源碼。我在這裏聲明下,我不會去發任何我覺得已經在博客裏介紹的非常清楚的實例的源碼,有些實例我已經把所有代碼都貼出來了,還是有人要源碼。。。我希望看我博客的朋友都能真正理解這個實例,能學到更多的知識,最好能有自己的改進然後再和大家一起分享。很多朋友現在已經習慣了拿別人的源碼,功能類似的就直接搬到自己項目裏,這是非常不好的習慣。動動手,多寫寫,你會學到更多。

轉自:http://www.cnblogs.com/noTice520/archive/2012/02/17/2355415.html
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章