ListView中新增CheckBox,進行多項選擇,全選,反選,完美無Bug
新手筆記:
最近做一個列表,實現批量選擇刪除功能,用到了ListView中新增的CheckBox,來進行多項選擇,全選,反選等。因為用到了ListView,故對新手來說,有很多坑。
1、由於ListView採用了Recycler,即重複利用convertView,所以用CheckBox時,容易出現選擇了前面一項,後面的某一項也被選中的情況。
2、有些新手由於實現方式有問題,容易出現只能選擇前面的可視範圍數量的item或者checkbox,選擇後面可能出現奔潰等。
3、又或者是想通過點選item,選中checkbox實現不了等。
在這裡分享一下我的實現方式,可供參考:
首先,我實現的效果是點選item直接就選中checkbox,實現方式在item的點選事件裡面改變checkbox的選中狀態等
只貼出核心部分的程式碼,item的佈局,和activity的佈局就不貼了,程式碼太多。網上都能找得到。
先貼出繼承自BaseAdapter的listview介面卡:
package com.example.Adapter; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import com.example.Utils.ImageLoader; import com.example.bean.CommonMusicInfo; import com.example.my_music.R; import com.example.my_music.R.drawable; import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.CheckBox; import android.widget.CompoundButton; import android.widget.CompoundButton.OnCheckedChangeListener; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; public class RecentPlayListAdapter extends BaseAdapter{ private List<CommonMusicInfo> musicList = new ArrayList<CommonMusicInfo>(); private LayoutInflater layoutInflater; private ImageLoader imageLoader; HashMap<Integer,String> cBSelectedList; // 將引用Activity的cBSelectedList的值 public static class ViewHolder{ TextView artist; TextView songTitle; ImageView imageView; ImageView littleIcon;
public static class ViewHolder{
TextView artist;
TextView songTitle;
ImageView imageView;
ImageView littleIcon;
LinearLayout llCheckBox;
LinearLayout llMore;
public CheckBox mCheckBox;
}
public RecentPlayListAdapter(Context context, List<CommonMusicInfo> list, HashMap<Integer,String> selectedlist) {this.cBSelectedList = selectedlist;this.musicList = list;
this.layoutInflater = LayoutInflater.from(context);
imageLoader = new ImageLoader(context); }@Overridepublic int getCount() {System.out.println("get count list.size() "+musicList.size());return musicList.size();}@Overridepublic Object getItem(int position) {return musicList.get(position);}@Overridepublic
long getItemId(int position) {return position;}public void updateList(List<CommonMusicInfo> list){musicList.clear();
musicList.addAll(list); }public void setCBSelectedList(HashMap<Integer,String> list){this.cBSelectedList = list;}public boolean isInSelectedList(int position){Iterator<Integer> keys =cBSelectedList.keySet().iterator(); //獲取HashMap的所以Value值while(keys.hasNext()){int key = keys.next();System.out.println("key="+key);if(key==position)
return true;}return false;}@Overridepublic View getView(final int position, View convertView, ViewGroup parent) {ViewHolder holder;if(convertView == null){ convertView = layoutInflater.inflate(R.layout.item_list_music, null); holder = new ViewHolder(); holder.artist
= (TextView) convertView.findViewById(R.id.id_artist); holder.songTitle = (TextView) convertView.findViewById(R.id.id_title); holder.imageView = (ImageView) convertView.findViewById(R.id.id_image); holder.littleIcon = (ImageView) convertView.findViewById(R.id.id_download_icon);
holder.mCheckBox = (CheckBox) convertView.findViewById(R.id.checkbox_musiclist); convertView.setTag(holder);
} else{
holder = (ViewHolder) convertView.getTag(); }holder.mCheckBox.setChecked(isInSelectedList(position));holder.littleIcon.setImageResource(drawable.icon_hq);holder.artist.setText(musicList.get(position).getAirtistName()); holder.songTitle.setText(musicList.get(position).getMusicName()); holder.imageView.setImageResource(R.drawable.list_default_img); if(musicList.get(position).getMusicType()==0){ imageLoader.showImageByAlbumId(musicList.get(position).getAlbumId(), holder.imageView); //若緩衝中有圖片就用緩衝,沒有則非同步從SD卡載入,並加入緩衝中
} else if(musicList.get(position).getMusicType()==1) { imageLoader.showImageByUrl(musicList.get(position).getSmallAlbumUrl(),holder.imageView);
}return convertView;}}
上面程式碼中要點的就是這幾段程式碼:
如果你的Adapter不是直接定義在Acitvity中的話,需要將ViewHolder改為public,CheckBoxy也是,因為待會要在Activity中用到。
public static class ViewHolder{
TextView artist;
TextView songTitle;
ImageView imageView;
ImageView littleIcon;
LinearLayout llCheckBox;
LinearLayout llMore;
public CheckBox mCheckBox;
}
得到裝了選中的checkbox(item)所在ListView中的位置的HashMap的引用,以及對於的歌曲id(這裡我裝這個資料是因為後面還要進行別的操作,可以根據需要改變)
public void setCBSelectedList(HashMap<Integer,String> list){
this.cBSelectedList = list;
}
這個方法用來判斷是否已經選中了,根據cBSelectedList中是否包含了該item的位置
public boolean isInSelectedList(int position){
Iterator<Integer> keys =cBSelectedList.keySet().iterator(); //獲取HashMap的所以Value值
while(keys.hasNext()){
int key = keys.next();
System.out.println("key="+key);
if(key==position) return true;
}
return false;
}
根據是否被選中,來改變CheckBox的狀態,主要為了防止ListView後面沒選中取顯示為選中狀態,因為Recycler的原因。
holder.mCheckBox.setChecked(isInSelectedList(position));
下面看Acitity中核心部分:
很簡單,不說太多
mListView.setOnItemClickListener(new OnItemClickListener(){
@Override
public void onItemClick(AdapterView<?> parent, View view, final int position, long id) {
if(recentPlayListAdapter.getShowCheckBox()){
RecentPlayListAdapter.ViewHolder holder = (RecentPlayListAdapter.ViewHolder) view.getTag();
holder.mCheckBox.toggle();
if(holder.mCheckBox.isChecked()){
cBSelectedList.put(position, list.get(position).getMusicId());
} else {
cBSelectedList.remove(position);
}
System.out.println(cBSelectedList);
}
}
});
然後,要刪除或者進行別的操作只需要根據cBSelectedList即可,裡面裝了所以選中的item項的位置。注意,進行刪除等操作後,要將cBSelectedList清空,然後更新Adapter裡面的listview的列表資料,最後recentPlayListAdapter.notifyDataSetChanged();
就寫這麼多吧,那些全選,反選的,如果理解了這種實現方法,那麼就很容易實現,只需要改變cBSelectedList即可。
本人為學生,手打不易,如有錯誤,歡迎指正學習。