新手笔记:
最近做一个列表,实现批量选择删除功能,用到了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 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;}}public static class ViewHolder{ TextView artist; TextView songTitle; ImageView imageView; ImageView littleIcon; LinearLayout llCheckBox; LinearLayout llMore; public CheckBox mCheckBox; }
上面代码中要点的就是这几段代码:如果你的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即可。
本人为学生,手打不易,如有错误,欢迎指正学习。