在Android開發中經常遇到使用ListView的情況,有時候需要的不僅僅是列表顯示,還有長按列表進行多選,並且批量刪除的情況,在這里記錄一下自己的所學。
先上效果圖:

幾個需要用到的核心方法:
//設置多選模式,下面的方法基於設置多選模式
list.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
//獲取Item選擇狀態:
list.isItemChecked(i);
//設置Item選擇狀態
list.setItemChecked(i, true);
//清除全部選中狀態
list.clearChoices();
簡述原理
多選模式下,ListView在觸發OnItemClick時會設置Item為true,再點一次為false,
我們只需創建一個isMultiplSelectionMode來傳遞判斷當前為多選模式,
在全選時遍歷list.setItemChecked()為true;
反選時遍歷list.isItemChecked(i)為true的set為false,false則為true,
刪除時直接遍歷list.isItemChecked(i)為true的在適配器上直接remove刪除即可
假裝深入源碼
我們知道ListView繼承AbsListView,
通過查看他的源碼的isItemChecked方法,可以看到
...
public boolean isItemChecked(int position) {
if (mChoiceMode != CHOICE_MODE_NONE && mCheckStates != null) {
return mCheckStates.get(position);
}
return false;
}
...
首先判斷了當前選擇模式不等於默認的單選模式 && mCheckStates 不為空的時候從這個mCheckStates去獲取當前的item的選擇狀態,那我們再來看看這個mCheckStates到底是什么?
/**
* Running state of which positions are currently checked
*/
SparseBooleanArray mCheckStates;
mCheckStates是SparseBooleanArray的實例,SparseBooleanArray實現了Cloneable接口,再往下就離題了,現在知道了mCheckStates本質是一個保存着Boolean的Array,並且這個Array與Items有關系,setItemChecked/isItemChecked都使用了mCheckStates,獲取的就是Item的狀態,邏輯他已經幫我們寫好,我們只用用好isItemChecked即可。
(好像說了和沒說一樣,尷尬了|;)
直接上源碼把
activity_main.xml
先界面:1個顯示選擇個數的TextView,3個Button,1個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"
android:orientation="vertical">
<LinearLayout
android:visibility="gone"
android:id="@+id/ItemToolBar"
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="選擇了0項"
android:id="@+id/counttext"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="全選"
android:id="@+id/all"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="反選"
android:id="@+id/unall"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="刪除"
android:id="@+id/del"/>
</LinearLayout>
<ListView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/mylistview"/>
</LinearLayout>
listview_item.xml
當然還有Item項的界面,簡單點,兩個TextView,一個標題,一個內容
<?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="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Large Text"
android:textAppearance="?android:attr/textAppearanceLarge"
android:id="@+id/lv_text1"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Small Text"
android:textAppearance="?android:attr/textAppearanceSmall"
android:id="@+id/lv_text2"/>
</LinearLayout>
MyAdapter.java
ListView的適配器,重寫了getView方法,讓當前可視部分的項目狀態為選中時改變背景顏色,關於geiView的ViewHolder部分可以看這的文章【Android開發中常用的ListView列表的優化方式ViewHolder】,簡而言之就是一種列表優化方式。
public class MyAdapter extends BaseAdapter {
public ArrayList<HashMap<String, Object>> balistItem = new ArrayList<HashMap<>>();
@Override
public int getCount() {
return balistItem.size();
}
@Override
public long getItemId(int p1) {
return p1);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder;
if (convertView == null) {
viewHolder = new ViewHolder();
convertView = View.inflate(MainActivity.CONTEXT, R.layout.listview_item, null);
viewHolder.title = convertView.findViewById(R.id.lv_text1);
viewHolder.text = convertView.findViewById(R.id.lv_text2);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder)convertView.getTag();
}
viewHolder.title.setText(balistItem.get(position).get("標題").toString());
viewHolder.text.setText(balistItem.get(position).get("內容").toString());
//判斷position位置是否被選中,改變顏色
if (MainActivity.list.isItemChecked(position) && MainActivity.isMultipleSelectionMode) {
convertView.setBackgroundColor(0xffff521d);
} else {
convertView.setBackgroundColor(0xff1E90FF);
}
return convertView;
}
public MyAdapter(List<? extends Map<String, ?>> data) {
this.balistItem = (ArrayList<HashMap<String, Object>>) data;
}
private static class ViewHolder {
TextView title;
TextView text;
public static ViewHolder newsInstance(View convertView) {
ViewHolder holder = (ViewHolder) convertView.getTag();
if (holder == null) {
holder = new ViewHolder();
holder.title = convertView.findViewById(R.id.lv_text1);
holder.text = convertView.findViewById(R.id.lv_text2);
convertView.setTag(holder);
}
return holder;
}
}
}
MainActivity.java
創建數據,並添加至適配器,設置長按進入多選模式,
public class MainActivity extends AppCompatActivity {
static ListView list;
static MyAdapter listItemAdapter;//適配器
static boolean isMultipleSelectionMode;//判斷進入多選模式
public static ArrayList<HashMap<String, Object>> AdapterList = new ArrayList<>(); //數據
public static Context CONTEXT;
TextView counttext;
LinearLayout ItemToolBar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
CONTEXT = this.getApplicationContext();
//初始化數據
initData();
counttext = this.findViewById(R.id.counttext);//選中時更改的textview
ItemToolBar = this.findViewById(R.id.ItemToolBar);//多選模式的工具欄
list.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
listItemAdapter = new MyAdapter(AdapterList); //新建並配置ArrayAapeter
list.setAdapter(listItemAdapter);
list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> p, View v, int index,
long arg3) {
if (isMultipleSelectionMode) {
setCountChange();
}
listItemAdapter.notifyDataSetChanged();
}
});
list.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
@Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long itemId) {
if (isMultipleSelectionMode) {
ItemToolBar.setVisibility(View.GONE);
isMultipleSelectionMode = false;
list.clearChoices();//取消選中狀態
Toast.makeText(CONTEXT, "退出多選模式", Toast.LENGTH_LONG).show();
} else {
ItemToolBar.setVisibility(View.VISABLE); isMultipleSelectionMode =true;
listItemAdapter.notifyDataSetChanged();
//多選模式
Toast.makeText(CONTEXT, "進入多選模式", Toast.LENGTH_LONG).show();
for(int i = 0;i < listItemAdapter.balistItem.size();i++){
Log.d("del","Item" + i + "的狀態:" + list.isItemChecked(i));
}
return true;
}
listItemAdapter.notifyDataSetChanged();
setCountChange();
return false;
}
});
//設置按鈕單機事件綁定
setButtonClick();
}
public void setCountChange(){
counttext.setText("選中了" + list.getCheckedItemCount() +"項");
}
public void initData(){
list = this.findViewById(R.id.mylistview);
for(int i = 0;i< 5;i++){
HashMap<String,Object> map = new HashMap<>();
map.put("標題","這是標題" + i);
map.put("內容","這是內容" + i);
AdapterList.add(map);
}
}
public void setButtonClick(){
Button all = this.findViewById(R.id.all);
Button unall = this.findViewById(R.id.unall);
Button del = this.findViewById(R.id.del);
all.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
for(int i = 0;i < listItemAdapter.balistItem.size();i++){
list.setItemChecked(i,true);
}
setCountChange();
}
});
unall.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
for(int i = 0;i < listItemAdapter.balistItem.size();i++){
if(list.isItemChecked(i)){
list.setItemChecked(i,false);
list.setItemChecked(i,false);
}else {
list.setItemChecked(i,true);
}
}
setCountChange();
}
});
del.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
for(int i = 0;i < listItemAdapter.balistItem.size();i++){
if(list.isItemChecked(i)){
listItemAdapter.balistItem.remove(i);
listItemAdapter.notifyDataSetChanged();
}
}
list.clearChoices();
setCountChange();
}
});
}
}
demo apk文件下載地址:https://files.cnblogs.com/files/zzerx/app-debug(1).apk
