前段時間要做一個批量刪除的功能,身爲初學者的我,開始嘗試做這個功能,但是出現了以下3個情況:
- checkbox被勾選上後,listview滑走再滑回來,本來應該被選中的checkbox成了未選中狀態
- 連續勾選後,刪除的不完整,比如我同時勾上了第3、4、5個item,點擊刪除後第3、5個倒是被刪除了,第4個沒有被刪除
- 亂序,明明選擇的是第2個,點擊刪除的時候,隨機的一個被刪除了
本來在網上查了一些解決的方法,但是都太複雜了(個人感覺),一個簡單的批量刪除,居然用map這麼高級的東西,所以我分享一下我解決的方法。
先上效果圖:
界面超級簡單,完全是爲了做批量刪除而的一個小例子,也沒有夾雜一些別的東西,比如全選反選之類的,我喜歡一篇文章只說一個問題,
使用到的類
- MainActivity:不解釋
- MyAdapter:listview的適配器
- Entity:實體類,封裝了listview的item的內容
接下來一個一個解釋,每個類到底有什麼東西
先說最簡的Entity類
代表着每一個item的內容
//是否被選中
private boolean isSelect;
//文本內容
private String text;
就兩個屬性,別的都是一些get、set方法,tostring什麼的。
接下來是MyAdapter類:
繼承BaseAdapter,實現對應的4個方法
以下是繼承BaseAdapter的常見手段(方法)
private ArrayList<Entity> datas = new ArrayList<>();
private LayoutInflater inflater;
public MyAdapter(Context context) {
inflater = LayoutInflater.from(context);
}
public void setList(ArrayList<Entity> list) {
this.datas = list;
}
現在說說最重要的getView方法
@Override
public View getView(int position, View convertView, ViewGroup parent) {
//使用viewholder優化listview
ViewHolder holder;
if (convertView == null) {
convertView = inflater.inflate(R.layout.item, null);
holder = new ViewHolder(convertView);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
//將position傳遞給checkbox監聽的實現類
//說白了就是讓chechbox知道它在listview的哪個位置
//好處就是,刪除的時候不會亂了,不會因爲選中的是a而把b刪了(解決亂序)
//因爲checkbox知道自己的位置了嘛
holder.checkbox.setTag(position);
holder.text.setText(datas.get(position).getText());
//給checkbox設置監聽
//使他被選中的時候做一些事情
//比如將對應的entity的isSelect改爲true
holder.checkbox.setOnCheckedChangeListener(listener);
//給checkbox設置狀態,是否被選中
//通過獲取對應的entity,取得裏面的isSelect的值修改
//解決選中後,listview滑動走再滑回來,checkbox又沒有選的尷尬
holder.checkbox.setChecked(datas.get(position).isSelect());
return convertView;
}
private CompoundButton.OnCheckedChangeListener listener = new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
//獲取傳遞來的position,點擊listview列表中的checkbox的時候,就能知道是點擊的哪個了
int pos = (int) buttonView.getTag();
//將集合中對應的entity中對應的isSelect設置爲checkbox的狀態(是否被選中true/false)
getItem(pos).setSelect(isChecked);
}
};
public static class ViewHolder {
public View rootView;
public TextView text;
public CheckBox checkbox;
public ViewHolder(View rootView) {
this.rootView = rootView;
this.text = (TextView) rootView.findViewById(R.id.text);
this.checkbox = (CheckBox) rootView.findViewById(R.id.checkbox);
}
}
準備工作都做完了,我們來看看MainActivity中的具體實現
佈局很簡單,線性佈局,方向垂直,上面一個批量刪除的按鈕,下面是listview。
先來感受一下MainActivity裏面的內容:
public class MainActivity extends AppCompatActivity {
private ListView listview;
private Button del;
private MyAdapter adapter;
private ArrayList<Entity> datas;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
datas = new ArrayList<>();
for (int i = 0; i < 30; i++) {
datas.add(new Entity(false, "item" + i));
}
listview = (ListView) findViewById(R.id.listview);
del = (Button) findViewById(R.id.del);
adapter = new MyAdapter(this);
adapter.addData(datas);
listview.setAdapter(adapter);
del.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
ArrayList<Entity> data = adapter.getData();
for (int i = 0; i < data.size(); i++) {
if (data.get(i).isSelect()) {
data.remove(i);
i--;
}
}
adapter.setList(data);
adapter.notifyDataSetChanged();
}
});
}
}
別的都沒上什麼說的,我們來看看點擊事件裏面有個i - -,這是幹嘛的呢,爲什麼要這麼寫呢,不寫會有什麼後果呢?
不寫的後果很嚴重,就是連續勾選item後,點擊刪除,不會全部被刪除,爲什麼會這樣,這要牽扯到ArrayList的結構。大家都知道ArrayList是類似數組的結構,所以,
來看一張我用畫圖工具畫的渣圖
該圖表示arraylist中有很多數據,其中梨子的位置是1,香蕉的位置是2,當我們刪除了梨子後,本來應該第2的香蕉,變成的位置1,也就是梨子後面所有的數據都想前挪動了一位(感覺好耗資源啊)
所以當我們連續選擇又沒有i- -時候,畫圖最清楚,上圖!
這裏解釋下:
圖1:當我們選中234的時候,實際上是將每一個item對應的entity中的isSelect值改爲了true。
圖2:點擊刪除後,系統開始循環遍歷整個集合,爲true就刪除,該循環只執行一次,
所以當循環到了位置2的時候,發現是true,不解釋直接刪除,此時集合中的數據位置爲圖2,
位置2已被item3代替
圖3:繼續循環,到了位置3,發現是item4,一看值爲true,直接刪,此時集合中的數據位置爲圖3
所以最終結果就是item3瞞天過海了。。。
結論
在for循環中,我們指定了循環的次數,int times = date.size(),但是當我們刪除了集合中的一個數據後,times已經發生改變了,爲了不使他改變,刪除一個就i- -一次,這樣,就能保證循環的次數和集合尺寸一樣了,就能完美實現批量刪除了。