1. 程式人生 > >ListView中新增CheckBox,進行多項選擇,全選,反選,完美無Bug

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即可。

本人為學生,手打不易,如有錯誤,歡迎指正學習。