[Android]实现ListView的删除功能

时间:2022-05-24 19:44:35

这里实现一个安卓开发中经常要开发的功能——ListView的删除功能。

实现说明:通过长按列表或者点击“编辑”按钮,显示每个列表项右边的复选框,选择复选框,点击“删除”按钮删除选中的列表项。

实现:

①主Activity的布局文件activity_main.xml:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity" >

	<ListView 
	    android:id="@+id/listview"
	    android:layout_width="fill_parent"
	    android:layout_height="fill_parent"
	    >
	</ListView>
	<LinearLayout
	    android:layout_width="fill_parent"
	    android:layout_height="wrap_content"
	    android:orientation="horizontal"
	    android:layout_alignParentBottom="true" >
	    <Button 
	        android:layout_width="0dp"
	        android:layout_height="wrap_content"
	        android:layout_weight="1"
	        android:text="编辑"
	        android:onClick="click_editButton"
	        />
	    <Button 
	        android:layout_width="0dp"
	        android:layout_height="wrap_content"
	        android:layout_weight="1"
	        android:text="删除"
	        android:onClick="click_deleteButton"
	        />
	    <Button 
	        android:layout_width="0dp"
	        android:layout_height="wrap_content"
	        android:layout_weight="1"
	        android:text="取消"
	        android:onClick="click_cancelButton"
	        />
	</LinearLayout>

</RelativeLayout>
②listview中item的布局文件list_item.xml:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="70dp"
    android:padding="5dp"
    android:background="#ffff00" >
    
    <TextView 
        android:id="@+id/textview"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="20sp"
        android:textColor="#000000"
        android:layout_centerVertical="true"
        />
    <CheckBox 
        android:id="@+id/checkbox"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_centerVertical="true"
        android:visibility="invisible"
        />

</RelativeLayout>
两个布局文件都很简单,样式都是随便定义的,大家瞄一眼就好。

③主Activity:

package com.example.listdelete;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemLongClickListener;
import android.widget.BaseAdapter;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.ListView;
import android.widget.TextView;

public class MainActivity extends Activity {
	private ListView listview;
	private MyAdapter myAdapter;
	/**列表的数据源*/
	private List<String> listData;
	/**记录选中item的下标*/
	private List<Integer> checkedIndexList;
	/**保存每个item中的checkbox*/
	private List<CheckBox> checkBoxList;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		initListData();
		initView();
	}
	/**初始化列表的数据源*/
	public void initListData() {
		//静态赋值
		listData = new ArrayList<String>();
		for(int i=0;i<6;i++){
			listData.add("item" + i);
		}
	}
	/**初始化控件*/
	public void initView(){
		listview = (ListView) findViewById(R.id.listview);
		myAdapter = new MyAdapter(getApplicationContext(), listData);
		listview.setAdapter(myAdapter);
		//监听listview的长按事件
		listview.setOnItemLongClickListener(new OnItemLongClickListener() {
			@Override
			public boolean onItemLongClick(AdapterView<?> arg0, View arg1,
					int arg2, long arg3) {
				//将checkbox设置为可见
				for(int i=0;i<checkBoxList.size();i++){
					checkBoxList.get(i).setVisibility(View.VISIBLE);
				}
				return false;
			}
		});
		
		checkedIndexList = new ArrayList<Integer>();
		checkBoxList = new ArrayList<CheckBox>();
	}
	/**自定义listview的适配器*/
	class MyAdapter extends BaseAdapter{
		private List<String> listData;
		private LayoutInflater inflater;
		public MyAdapter(Context context, List<String> listData){
			this.listData = listData;
			inflater = LayoutInflater.from(context);
		}
		@Override
		public int getCount() {
			return listData.size();
		}
		@Override
		public Object getItem(int arg0) {
			return listData.get(arg0);
		}
		@Override
		public long getItemId(int arg0) {
			return arg0;
		}
		@Override
		public View getView(int position, View convertView, ViewGroup parent) {
			ViewHolder viewHolder;
			if(convertView == null){
				viewHolder = new ViewHolder();
				convertView = inflater.inflate(R.layout.list_item, null);
				viewHolder.tv = (TextView) convertView.findViewById(R.id.textview);
				viewHolder.checkbox = (CheckBox) convertView.findViewById(R.id.checkbox);
				//将item中的checkbox放到checkBoxList中
				checkBoxList.add(viewHolder.checkbox);
				convertView.setTag(viewHolder);
			}else{
				viewHolder = (ViewHolder) convertView.getTag();
			}
			viewHolder.tv.setText(listData.get(position));
			viewHolder.checkbox.setOnCheckedChangeListener(new CheckBoxListener(position));
			return convertView;
		}
	    class ViewHolder{
	        TextView tv;
	        CheckBox checkbox;
	    }
	}
	/**checkbox的监听器*/
	class CheckBoxListener implements OnCheckedChangeListener{
		/**列表item的下标位置*/
		int position;
		public CheckBoxListener(int position){
			this.position = position;
		}
		@Override
		public void onCheckedChanged(CompoundButton arg0, boolean isChecked) {
			if(isChecked){
				checkedIndexList.add(position);
			}else{
				checkedIndexList.remove((Integer)position);
			}
		}
	}
	/**编辑按钮的点击事件*/
	public void click_editButton(View v){
		//将checkbox设置为可见
		for(int i=0;i<checkBoxList.size();i++){
			checkBoxList.get(i).setVisibility(View.VISIBLE);
		}
	}
	/**删除按钮的点击事件*/
	public void click_deleteButton(View v){
		//先将checkedIndexList中的元素从大到小排列,否则可能会出现错位删除或下标溢出的错误
		checkedIndexList = sortCheckedIndexList(checkedIndexList);
		for(int i=0;i<checkedIndexList.size();i++){
			//需要强转为int,才会删除对应下标的数据,否则默认删除与括号中对象相同的数据
			listData.remove((int)checkedIndexList.get(i));
			checkBoxList.remove(checkedIndexList.get(i));
		}
		for(int i=0;i<checkBoxList.size();i++){
			//将已选的设置成未选状态
			checkBoxList.get(i).setChecked(false);
			//将checkbox设置为不可见
			checkBoxList.get(i).setVisibility(View.INVISIBLE);
		}
		//更新数据源
		myAdapter.notifyDataSetChanged();
		//清空checkedIndexList,避免影响下一次删除
		checkedIndexList.clear();
	}
	/**取消按钮的点击事件*/
	public void click_cancelButton(View v){
		for(int i=0;i<checkBoxList.size();i++){
			//将已选的设置成未选状态
			checkBoxList.get(i).setChecked(false);
			//将checkbox设置为不可见
			checkBoxList.get(i).setVisibility(View.INVISIBLE);
		}
	}
	/**对checkedIndexList中的数据进行从大到小排序*/
	public List<Integer> sortCheckedIndexList(List<Integer> list){
		int[] ass = new int[list.size()];//辅助数组
		for(int i=0;i<list.size();i++){
			ass[i] = list.get(i);
		}
		Arrays.sort(ass);
		list.clear();
		for(int i=ass.length-1;i>=0;i--){
			list.add(ass[i]);
		}
		return list;
	}
}

讲解:

好,因为注释很详细,大家应该能看懂,接下来主要来讲解主Activity中的一些知识点:

1)首先是自定义适配器,继承自BaseAdapter,来作为listview 的适配器,这里涉及到BaseAdapter的最佳实现方式,即文艺式,大家可自行百度。

2)其次,我定义了List<Integer> checkedIndexList来记录选中的item的下标,以及List<CheckBox> checkBoxList来存放每个item的复选框,这在删除过程中都会用到。

3)删除的时候,要特别注意需将要删除的下标进行从大到小排列,否则会出现错位删除或下标溢出的情况,大家可自行调试。所以,在实际项目中,删除的时候我们可能还需要对数据源作相应的操作。

4)同时,还要特别注意删除数据源listData中数据的时候,我们是按照下标来删除相应的数据,但是checkedIndexList.get(i)得到的是Object对象,所以要强转为int类型。


优化:

最后再说一下该代码段中可以优化的一个地方吧:在MyAdapter中,每个checkbox设置监听器的时候都new了一个CheckBoxListener对象,这样如果列表项很多的话,new出这么多对象对内存也造成了很大的压力,而且这些对象都是实现同样的功能,所以可以用单例模式来做优化。但是有时候我们需要将不同列表项的position传到监听器中,根据position来做处理,这时可以重构需要设置监听器的控件,比如这个代码段中的CheckBox,将position作为成员变量即可。


好了,这个功能就这样实现啦,希望对你有帮助!