ListView中有一個屬性:android:choiceMode,對應三個可選值:
- singleChoice 單選
- multipleChoice 多選
- none 默認情況,沒有選中效果
在ListView的佈局中設置了android:choiceMode屬性後,item佈局需要實現checkable,纔有選中效果。
那麼我們先來看一下這個checkable接口:
/**
* Defines an extension for views that make them checkable.
*
*/
public interface Checkable {
/**
* Change the checked state of the view
*
* @param checked The new checked state
*/
void setChecked(boolean checked);
/**
* @return The current checked state of the view
*/
boolean isChecked();
/**
* Change the checked state of the view to the inverse of its current state
*
*/
void toggle();
}
接口很簡單,就三個方法:
- setChecked(boolean checked) 設置是否選中。當我們點擊item的時候,會調用這個方法。
- boolean isChecked() 判斷是否選中。
- toggle() 開關,如果當前是選中的狀態,調用該方法後取消選中,反之,選中。
實現單選效果:
1、 ListView佈局中android:choiceMode設置爲singleChoice。
2、選取實現了checkable接口的View或者ViewGroup作爲item佈局控件。
當item展示的數據比較簡單,例如就是一段文本,item佈局可以直接使用系統自帶的CheckedTextView控件,該控件有一個屬性:android:checkMark=”?android:listChoiceIndicatorSingle”爲單選樣式;“?android:listChoiceIndicatorMultiple”爲多選樣式。若要修改顯示的樣式,可以自己寫一個selector,然後checkMark指定爲這個selector。例如:
在drawable文件夾下面創建一個ic_hideable_item.xml文件。
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="false" android:drawable="@mipmap/ic_hideable_item_unchecked" />
<item android:drawable="@mipmap/ic_hideable_item_checked" />
</selector>
checkMark指定爲上面的那個xml文件:
<CheckedTextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/tv_single_choice"
android:layout_width="match_parent"
android:layout_height="?android:attr/listPreferredItemHeightSmall"
android:textSize="14sp"
android:gravity="center_vertical"
android:checkMark="@drawable/ic_hideable_item"
android:paddingLeft="16dp"
android:paddingRight="16dp">
</CheckedTextView>
實現多選效果:
1、 ListView佈局中android:choiceMode設置爲multipleChoice。
2、選取實現了checkable接口的View或者ViewGroup作爲item佈局控件。
這裏筆者自定義一個控件實現Checkable接口。代碼如下:
public class CheckableLayout extends RelativeLayout implements Checkable {
private static final int[] CHECKED_STATE_SET = {android.R.attr.state_checked};
private boolean mChecked;
public CheckableLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public void setChecked(boolean b) {
if (b != mChecked){
mChecked = b;
refreshDrawableState();
}
}
@Override
public boolean isChecked() {
return mChecked;
}
@Override
public void toggle() {
setChecked(!mChecked);
}
@Override
protected int[] onCreateDrawableState(int extraSpace) {
final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
if (isChecked()) mergeDrawableStates(drawableState, CHECKED_STATE_SET);
return drawableState;
}
}
應用到item佈局:
<com.jm.customchoicelist.CheckableLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="@+id/tv_content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:duplicateParentState="true"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:layout_marginLeft="30dp"
android:textColor="@color/hideable_text_color"
tools:text="測試數據"/>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:duplicateParentState="true"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginRight="20dp"
android:src="@drawable/ic_hideable_item"/>
</com.jm.customchoicelist.CheckableLayout>
注意到上面TextView、ImageView控件中的android:duplicateParentState屬性,
該屬性表示當前控件是否跟隨父控件的狀態(點擊、焦點等)。若將TextView的該屬性置爲false,則文字無變色效果;若將ImageView的該屬性置爲false,則無選中效果。
最後怎樣獲取選中item對應的位置呢?
- 單選—> 通過ListView的getCheckedItemPosition()獲取選中的位置。
- 多選—> 通過ListView的getCheckedItemPositions()得到一個SparseBooleanArray,key爲position,value爲是否選中。
mSingleListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
int checkedItemPosition = mSingleListView.getCheckedItemPosition();
Toast.makeText(MainActivity.this, "you chose item " + checkedItemPosition, Toast.LENGTH_SHORT).show();
}
});
mMultipleListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
SparseBooleanArray checkedItemPositions = mMultipleListView.getCheckedItemPositions();
boolean isChecked = checkedItemPositions.get(position);
Toast.makeText(MainActivity.this, "item " + position + " isChecked=" + isChecked, Toast.LENGTH_SHORT).show();
}
});