1. 程式人生 > >最簡潔程式碼實現Listview多選

最簡潔程式碼實現Listview多選

記得剛開始學android開發時要實現Listview多選然後批量操作的時候,用Checkbox+Textview,因為adapter複用後上下翻頁的時候Checkbox狀態無法儲存,然後用一個全域性變數記住該狀態,翻頁的時候再恢復狀態。現在想想這麼搞不僅low爆了,而且效率低。由於最近專案又需要實現類似的功能,想想不能重蹈覆轍,於是谷歌了一把,看到CheckedTextView,原來谷歌工程師已經幫我們實現了類似的功能。本來以為很簡單,隨便兩下就搞定,等到自己動手,才發現不是那麼回事,於是寫下此文記錄下來。

先來看完整的過程:
1.新增控制元件

<ListView
    android:id
="@+id/lvMain" android:layout_width="match_parent" android:layout_height="match_parent" android:choiceMode="multipleChoice" />

2.設定資料

for (int i=0;i<100;i++)
        {     mDataList.add("item--"+i);     }
MyBaseAdapterListview<String>adapter=new MyBaseAdapterListview<String>(this
,mDataList,android.R.layout.simple_list_item_multiple_choice,true) { @Override public void convert(MyViewHolderExpandbleListView holder, String s, int position) { CheckedTextView checkedTextView = holder.getView(android.R.id.text1); checkedTextView.setText(s); } };

上面MyBaseAdapterListview是我自己封裝的一個Adapter類,用來填充Listview資料,是不是簡單易用?工具包含三個類,Demo裡面有,可以直接拿來用。也可以從github引用,地址為

https://github.com/crook3/ExpandableListviewAdapter
3.監聽點選事件

lvMain.setOnItemClickListener(new AdapterView.OnItemClickListener() {
    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
        sparseBooleanArray=lvMain.getCheckedItemPositions();
        int size=sparseBooleanArray.size();
        String result = "";
        for (int i=0;i<size;i++)
        {
            if (sparseBooleanArray.valueAt(i))result+=sparseBooleanArray.keyAt(i)+"*";
        }
        Toast.makeText(MainActivity.this,result,Toast.LENGTH_LONG).show();
    }
});

執行結果:
image

OK,完美!
使用系統提供的佈局方便簡單,不用自己管理Checkbox的狀態了,多麼美好啊。但是有時候並不能滿足我們的需求,比如說需要新增一張圖片。這個時候就需要自定義了Listview的item的佈局了,好,那直接來一個LinearLayout,裡面包Imageview和 CheckedTextView,不就可以了嗎。恩,你還是太年輕了,如果這麼搞你會發現chechbox的狀態無法像之前進行自我管理了,這應該是因為CheckedTextView
不再是根佈局導致系統無法管理。所以最後,為了保證CheckedTextView就是根佈局,我們只能如下佈局activity_main_item:

<CheckedTextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/tv1"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:gravity="center_vertical"
    android:checkMark="?android:attr/listChoiceIndicatorMultiple"
    android:drawableLeft="@mipmap/ic_launcher"
    />

然後新增資料來源的時候採用在一個Textview裡面進行換行的思想來實現多行的效果,這樣以最少的程式碼基本滿足我們的需求了。

mDataList.add("item--"+i+" \n test1 \n test2");
MyBaseAdapterListview<String>adapter=new MyBaseAdapterListview<String>(this,mDataList,R.layout.activity_main_item,true) {
            @Override
            public void convert(MyViewHolderExpandbleListView holder, String s, int position) {
                 CheckedTextView  checkedTextView = holder.getView(R.id.tv1);
                checkedTextView.setText(s);
           }
       };

自定義佈局執行介面
image

自定義複選框顏色及左右,

android:checkMarkTint="@android:color/holo_green_dark"
    android:checkMark="?android:attr/listChoiceIndicatorMultiple"
    android:drawableTint="@android:color/holo_blue_bright"
    android:drawableLeft="?android:attr/listChoiceIndicatorMultiple"

執行結果

image

如果想子item文字之間間隔更大,使用android:lineSpacingExtra="10dp"

image

至此,整個過程結束,相信大家使用起來沒什麼問題了。

有兩點需要說明
1、從 class CheckedTextView extends TextView implements Checkable看出CheckedTextView 兼具Textview和CheckBox特性。
2、lvMain.getCheckedItemPositions()的返回值用SparseBooleanArray陣列接收,要知道通過鍵值對的方式去取值sparseBooleanArray.valueAt(i)和sparseBooleanArray.keyAt(i)。