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 musicList = new ArrayList();
	private LayoutInflater layoutInflater;
	private ImageLoader imageLoader;
	HashMap 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 list, HashMap 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 list){musicList.clear(); musicList.addAll(list); }public void setCBSelectedList(HashMap list){this.cBSelectedList = list;}public boolean isInSelectedList(int position){Iterator 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 list){
		this.cBSelectedList = list;
	}

这个方法用来判断是否已经选中了,根据cBSelectedList中是否包含了该item的位置

public boolean isInSelectedList(int position){		
		Iterator 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即可。

本人为学生,手打不易,如有错误,欢迎指正学习。





你可能感兴趣的:(ListView中添加CheckBox,进行多项选择,全选,反选,完美无Bug)