Android 实现ListView的A-Z字母排序及过滤搜索功能(通讯录)

   最近在做的项目中有个通讯录功能,里面实现了ListView的A-Z排序以及对通讯录中的联系人按 汉字姓名、拼音姓名、手机号码进行搜索(过滤),详细过程如下:

   1、联系人实体类,通讯录部分用到了name(联系人姓名)、pinyin(联系人姓名拼音)、header(联系人拼音首字母),具体如下:

package com.bean.note;

public class PersonBean {

	private String id;
	private String name;
	private String region;
	private String department;
	private String position;
	private String isOften;
	private String permission;
	private boolean ischeck;

	private String pinyin;
	private String header;

	private String email;
	private String mobilePhone;
	private String telephone;
	private String sex;
	private String groupId;
	private String headImagePath;

	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getRegion() {
		return region;
	}

	public void setRegion(String region) {
		this.region = region;
	}

	public String getDepartment() {
		return department;
	}

	public void setDepartment(String department) {
		this.department = department;
	}

	public String getPosition() {
		return position;
	}

	public void setPosition(String position) {
		this.position = position;
	}

	public String getPermission() {
		return permission;
	}

	public void setPermission(String permission) {
		this.permission = permission;
	}

	public String getIsOften() {
		return isOften;
	}

	public void setIsOften(String isOften) {
		this.isOften = isOften;
	}

	public String getPinyin() {
		return pinyin;
	}

	public void setPinyin(String pinyin) {
		this.pinyin = pinyin;
	}

	public String getHeader() {
		return header;
	}

	public void setHeader(String header) {
		this.header = header;
	}

	public String getEmail() {
		return email;
	}

	public void setEmail(String email) {
		this.email = email;
	}

	public String getMobilePhone() {
		return mobilePhone;
	}

	public void setMobilePhone(String mobilePhone) {
		this.mobilePhone = mobilePhone;
	}

	public String getTelephone() {
		return telephone;
	}

	public void setTelephone(String telephone) {
		this.telephone = telephone;
	}

	public String getSex() {
		return sex;
	}

	public void setSex(String sex) {
		this.sex = sex;
	}

	public String getGroupId() {
		return groupId;
	}

	public void setGroupId(String groupId) {
		this.groupId = groupId;
	}

	public String getHeadImagePath() {
		return headImagePath;
	}

	public void setHeadImagePath(String headImagePath) {
		this.headImagePath = headImagePath;
	}

	public boolean getIscheck() {
		return ischeck;
	}

	public void setIscheck(boolean ischeck) {
		this.ischeck = ischeck;
	}

}
 2.Sidebar类就是ListVIew右侧显示的A-Z字母索引的VIew,我们需要使用setHeaderTextAndscroll(MotionEvent event)来实现当按下右侧索引字母时在屏幕中间显示所按下的字母及listVIew定位到我们所按下字母的位置,具体代码如下:

package com.contactlist;

import com.adapter.contact.ContactAdapter;
import com.l2cplat.l2cplat.R;
import com.util.DensityUtil;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Align;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ListView;
import android.widget.TextView;

public class Sidebar extends View {

	private Paint paint;
	private TextView header;
	private float height;
	private ListView myListView;
	private Context context;

	private String[] sections = new String[] { "A", "B", "C", "D", "E", "F",
			"G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S",
			"T", "U", "V", "W", "X", "Y", "Z", "#" };

	public void setListView(ListView listView) {
		myListView = listView;
	}

	public Sidebar(Context context, AttributeSet attrs) {
		super(context, attrs);
		this.context = context;
		init();
	}

	private void init() {
		paint = new Paint(Paint.ANTI_ALIAS_FLAG);
		paint.setColor(Color.DKGRAY);// 设置绘制的颜色
		paint.setTextAlign(Align.CENTER);// 设置绘制文子的对齐方式
		paint.setTextSize(DensityUtil.dip2px(context, 15));// 设置绘制文字的字号大小
	}

	@Override
	protected void onDraw(Canvas canvas) {
		super.onDraw(canvas);
		float center = getWidth() / 2;
		height = getHeight() / sections.length;
		for (int i = sections.length - 1; i > -1; i--) {
			canvas.drawText(sections[i], center, height * (i + 1), paint);
			// paint.reset();// 重置画笔
		}
	}

	private int sectionForPoint(float y) {
		int index = (int) (y / height);
		if (index < 0) {
			index = 0;
		}
		if (index > sections.length - 1) {
			index = sections.length - 1;
		}
		return index;
	}

	private void setHeaderTextAndscroll(MotionEvent event) {
		if (myListView == null) {
			// check the mListView to avoid NPE. but the mListView shouldn't be
			// null
			// need to check the call stack later
			return;
		}
		String headerString = sections[sectionForPoint(event.getY())];
		header.setText(headerString);
		ContactAdapter adapter = (ContactAdapter) myListView.getAdapter();
		int position = adapter.getPositionForSection(headerString.charAt(0));
		if (position != -1) {
			myListView.setSelection(position);
		}

	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		switch (event.getAction()) {
		case MotionEvent.ACTION_DOWN: {
			if (header == null) {
				header = (TextView) ((View) getParent())
						.findViewById(R.id.floating_header);
			}
			setHeaderTextAndscroll(event);
			header.setVisibility(View.VISIBLE);
			setBackgroundResource(R.drawable.sidebar_background_pressed);
			return true;
		}
		case MotionEvent.ACTION_MOVE: {
			setHeaderTextAndscroll(event);
			return true;
		}
		case MotionEvent.ACTION_UP:
			header.setVisibility(View.INVISIBLE);
			setBackgroundColor(Color.TRANSPARENT);
			return true;
		case MotionEvent.ACTION_CANCEL:
			header.setVisibility(View.INVISIBLE);
			setBackgroundColor(Color.TRANSPARENT);
			return true;
		}
		return super.onTouchEvent(event);
	}

}

3.ContactAdapter数据的适配器类,该类需要实现SectionIndexer接口,该接口是用来控制ListVIew分组的,该接口有三个方法 getSectionForPosition(int position)、getPositionForSection(int section)、getSections(),我们只需要自行实现前两个方法

  • getSectionForPosition(int position),是根据ListView的position来获取该位置上面的name的首字母char的ascii值,例如:如果该position上面的name是白总,首字母就是B,那么该方法返回的就是'A'字母的ascii值
  • getPositionForSection(int section),就是根据首字母的ascii值来获取在该ListView中第一次出现该首字母的位置
  • getView(int position, View convertView, ViewGroup parent),首先我们根据ListView的position调用getSectionForPosition(int position)来获取该位置上面name的首母的ascii值,然后根据这个ascii值调用getPositionForSection(int section)来获取第一次出现该首字母的position,如果ListView的position等于根据这个ascii值调用getPositionForSection(int section)来获取第一次出现该首字母的positiion,则显示分类字母,否则隐藏
       具体代码如下:
 
package com.adapter.contact;

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

import com.bean.note.PersonBean;
import com.l2cplat.l2cplat.R;
import android.annotation.SuppressLint;
import android.content.Context;
import android.util.SparseBooleanArray;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.SectionIndexer;
import android.widget.TextView;

public class ContactAdapter extends BaseAdapter implements SectionIndexer {

	public static SparseBooleanArray isSelected;
	private ArrayList myPersonBeans;
	private Context myContext;
	private LayoutInflater inflater;
	private int myFlag = -1;
	private List myOrgIds;

	public ContactAdapter(Context context, ArrayList personBeans,
			int flag, List orgIds) {
		this.myContext = context;
		this.myPersonBeans = personBeans;
		this.myFlag = flag;
		inflater = LayoutInflater.from(myContext);
		if (myFlag == 1) {
			this.myOrgIds = orgIds;
			init();
		}
	}

	private void init() {
		isSelected = new SparseBooleanArray(myPersonBeans.size());
		for (int i = 0; i < myPersonBeans.size(); i++) {
			if (myOrgIds.size() == 0) {
				isSelected.put(i, false);
			} else {
				for (int j = 0; j < myOrgIds.size(); j++) {
					if (myPersonBeans.get(i).getId().equals(myOrgIds.get(j))) {
						isSelected.put(i, true);
					} else if (!myPersonBeans.get(i).getId()
							.equals(myOrgIds.get(j))
							&& j == myOrgIds.size() - 1) {
						if (!isSelected.get(i)) {
							isSelected.put(i, false);
						}
					}
				}
			}
		}
	}

	@Override
	public int getCount() {
		return myPersonBeans.size();
	}

	@Override
	public PersonBean getItem(int position) {
		return myPersonBeans.get(position);
	}

	@Override
	public long getItemId(int position) {
		return 0;
	}

	@Override
	public View getView(int position, View convertView, ViewGroup parent) {

		if (convertView == null) {
			convertView = inflater.inflate(R.layout.contact_item, null);
		}

		ImageView checkIv = (ImageView) convertView
				.findViewById(R.id.check_btn);
		if (myFlag == 1) {
			checkIv.setVisibility(View.VISIBLE);
		} else {
			checkIv.setVisibility(View.GONE);
		}
		TextView headerTv = (TextView) convertView.findViewById(R.id.header);
		ImageView personIv = (ImageView) convertView
				.findViewById(R.id.contact_iv);
		TextView nameTv = (TextView) convertView.findViewById(R.id.contact_tv);

		PersonBean personBean = getItem(position);

		// 根据position获取分类的首字母的char ascii值
		int section = getSectionForPosition(position);

		// 如果当前位置等于该分类首字母的Char的位置,则认为是第一次出现
		if (position == getPositionForSection(section)) {
			headerTv.setVisibility(View.VISIBLE);
			headerTv.setText(personBean.getHeader());
		} else {
			headerTv.setVisibility(View.GONE);
		}

		if ("1".equals(personBean.getSex())) {
			personIv.setImageResource(R.drawable.male_s);
		} else {
			personIv.setImageResource(R.drawable.female_s);
		}

		if (myFlag == 1) {
			if (isSelected.get(position)) {
				checkIv.setImageResource(R.drawable.all_day_btn02);
			} else {
				checkIv.setImageResource(R.drawable.all_day_btn01);
			}
		}
		nameTv.setText(personBean.getName());

		return convertView;
	}

	/**
	 * 根据分类的首字母的Char ascii值获取其第一次出现该首字母的位置
	 */
	@SuppressLint("DefaultLocale")
	@Override
	public int getPositionForSection(int section) {
		for (int i = 0; i < getCount(); i++) {
			String sortStr = myPersonBeans.get(i).getHeader();
			char firstChar = sortStr.toUpperCase().charAt(0);
			if (firstChar == section) {
				return i;
			}
		}
		return -1;
	}

	/**
	 * 根据ListView的当前位置获取分类的首字母的char ascii值
	 */
	@Override
	public int getSectionForPosition(int position) {
		return myPersonBeans.get(position).getHeader().charAt(0);
	}

	@Override
	public Object[] getSections() {

		return null;
	}

}
4.ContactlistFragment这里面的代码比较简单主要用到了NameSort对通讯录的联系人首先按首字母进行排序,首字母相同则按姓名拼音排序,具体代码如下:
package com.contactlist;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.message.BasicNameValuePair;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.AdapterView.OnItemLongClickListener;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.ListView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;
import com.activity.base.BaseSlidingFragment;
import com.adapter.contact.ContactAdapter;
import com.baidu_lbs.LocationApplication;
import com.bean.note.PersonBean;
import com.http.AsyncGET;
import com.l2cplat.l2cplat.MainFragmentActivity;
import com.l2cplat.l2cplat.R;
import com.l2cplat.l2cplat.MainFragmentActivity.OnCurrentListener;
import com.l2cplat.l2cplat.MainFragmentActivity.OnMainListener;
import com.slidingmenu.SlidingMenu;
import com.util.API;
import com.util.JSONUtil;
import com.util.NameSort;
import com.util.NoteUtil;

public class ContactlistFragment extends BaseSlidingFragment implements
		OnCurrentListener, OnMainListener, OnClickListener {

	public static SlidingMenu mSlidingMenu;
	private ImageButton slidingBtn;
	private ImageButton seekBtn;
	private Button groupBtn;
	private TextView topTv;
	private ListView contactLv;
	private Sidebar sidebar;

	private RelativeLayout searchRl;

	private NoteUtil noteUtil;
	private JSONUtil jsonUtil = null;

	private MainFragmentActivity myActivity = null;
	private static ProgressDialog myDialog = null;

	private LoadDataAsyncTask asyncTask;

	private ArrayList personBeans = null;
	private ContactAdapter adapter;
	private String tokenValue = "-1";

	private NameSort nameSort = null;

	private String mobilePhone = "";
	private String emailTo;
	private String personId = "";
	private Resources r;

	private int index = 0;
	private int top = 0;

	private String type = "-1";

	@Override
	public void onAttach(Activity activity) {
		super.onAttach(activity);
	}

	@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container,
			Bundle savedInstanceState) {
		return inflater.inflate(R.layout.contact_list, container, false);
	}

	@Override
	public void onActivityCreated(Bundle savedInstanceState) {
		super.onActivityCreated(savedInstanceState);
		initWidget();
		getUserInfo();

	}

	@Override
	public void onResume() {
		super.onResume();
		LocationApplication.initData(getActivity());
		asyncTask = new LoadDataAsyncTask();
		asyncTask.execute("all");
	}

	@Override
	public void onStop() {
		super.onStop();
		// 保存当前第一个可见的item的索引和偏移量
		index = contactLv.getFirstVisiblePosition();
		View v = contactLv.getChildAt(0);
		top = (v == null) ? 0 : v.getTop();
	}

	/**
	 * 获取登录用户的ID
	 */
	private void getUserInfo() {
		SharedPreferences shared = getActivity().getSharedPreferences(
				"UserInfo", 0);
		tokenValue = shared.getString("tokenValue", "-1");
	}

	private void initWidget() {
		myActivity = new MainFragmentActivity();
		noteUtil = new NoteUtil();
		jsonUtil = new JSONUtil();

		mSlidingMenu = (SlidingMenu) getActivity().findViewById(
				R.id.slidingmenu);
		mSlidingMenu.setTouchModeAbove(SlidingMenu.TOUCHMODE_MARGIN);// 设置侧边栏的滑出方式(屏幕边沿)

		slidingBtn = (ImageButton) getView().findViewById(R.id.note_cebian_btn);
		seekBtn = (ImageButton) getView().findViewById(R.id.note_seek_btn);
		groupBtn = (Button) getView().findViewById(R.id.share_btn);
		topTv = (TextView) getView().findViewById(R.id.note_top_tv);

		searchRl = (RelativeLayout) getView().findViewById(R.id.search_rl);

		contactLv = (ListView) getView().findViewById(R.id.contact_lv);
		sidebar = (com.contactlist.Sidebar) getView()
				.findViewById(R.id.sidebar);
		sidebar.setListView(contactLv);
		contactLv.setVerticalScrollBarEnabled(false);

		topTv.setText("通讯录");

		slidingBtn.setImageResource(R.drawable.btn_cebian_2x);
		seekBtn.setVisibility(View.GONE);
		groupBtn.setVisibility(View.VISIBLE);
		groupBtn.setText("群 发");
		slidingBtn.setOnClickListener(this);
		seekBtn.setOnClickListener(this);
		groupBtn.setOnClickListener(this);

		searchRl.setOnClickListener(this);

		contactLv.setOnItemClickListener(new OnItemClickListener() {

			@Override
			public void onItemClick(AdapterView parent, View view,
					int position, long id) {
				personId = personBeans.get(position).getId();
				Intent intent = new Intent(getActivity(), ContactDetails.class);
				Bundle bundle = new Bundle();
				bundle.putString("personId", personId);
				intent.putExtras(bundle);
				startActivity(intent);
			}
		});

		contactLv.setOnItemLongClickListener(new OnItemLongClickListener() {

			@Override
			public boolean onItemLongClick(AdapterView parent, View view,
					int position, long id) {

				mobilePhone = personBeans.get(position).getMobilePhone();
				emailTo = personBeans.get(position).getEmail();
				// emailTo = "[email protected]";
				System.out.println("--mobilePhone--:" + mobilePhone
						+ "--emailTo--:" + emailTo);
				if (mobilePhone != null && !"".equals(mobilePhone)) {
					AlertDialog.Builder builder = new AlertDialog.Builder(
							getActivity());
					builder.setItems(setChoice(),
							new DialogInterface.OnClickListener() {

								@Override
								public void onClick(DialogInterface dialog,
										int which) {
									switch (which) {
									case 0:
										Intent intent = new Intent(
												Intent.ACTION_CALL, Uri
														.parse("tel:"
																+ mobilePhone));
										startActivity(intent);
										break;
									case 1:
										Uri uri = Uri.parse("smsto://"
												+ mobilePhone);

										Intent intent01 = new Intent(
												Intent.ACTION_SENDTO, uri);
										startActivity(intent01);
										break;
									case 2:
										Intent intent02 = new Intent(
												Intent.ACTION_SENDTO, Uri
														.parse("mailto:"
																+ emailTo));
										intent02.putExtra(Intent.EXTRA_SUBJECT,
												"");
										intent02.putExtra(Intent.EXTRA_TEXT, "");
										startActivity(intent02);
										break;
									}
								}
							}).create().show();
					builder.setCancelable(true);
					builder.create().setCanceledOnTouchOutside(true);
				} else {
					Toast.makeText(getActivity(), "该联系人没有录入联系电话",
							Toast.LENGTH_SHORT).show();
				}

				return true;
			}
		});
	}

	/**
	 * Loads a String array asset into a array.
	 * 
	 * @return
	 */
	private String[] setChoice() {
		r = this.getResources();
		return r.getStringArray(R.array.contact_type);
	}

	/**
	 * Loads a String array asset into a array.
	 * 
	 * @return
	 */
	private String[] setGroupChoice() {
		r = this.getResources();
		return r.getStringArray(R.array.group_to_type);
	}

	/**
	 * 跳转到选人界面
	 */
	private void setIntent() {
		Intent intent = new Intent(getActivity(), SelectContact.class);
		Bundle bundle = new Bundle();
		bundle.putString("type", type);
		intent.putExtras(bundle);
		startActivity(intent);
	}

	@Override
	public void onClick(View v) {
		switch (v.getId()) {
		case R.id.note_cebian_btn:
			if (mSlidingMenu.getMode() == 2) {
				mSlidingMenu.showMenu();
			}
			break;
		case R.id.search_rl:
			System.out.println("--点击搜索框--");
			Intent intent = new Intent(getActivity(), SearchContact.class);
			startActivity(intent);
			break;
		case R.id.share_btn:
			AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
			builder.setItems(setGroupChoice(),
					new DialogInterface.OnClickListener() {

						@Override
						public void onClick(DialogInterface dialog, int which) {
							switch (which) {
							case 0:
								type = "note";
								setIntent();
								break;
							case 1:
								type = "email";
								setIntent();
								break;
							}
						}
					}).create().show();
			builder.setCancelable(true);
			break;
		}
	}

	private class LoadDataAsyncTask extends AsyncTask {

		/**
		 * 开始执行异步线程
		 */
		@Override
		protected void onPreExecute() {
			super.onPreExecute();
			myDialog = myActivity.showProgressDialog("数据加载中...", getActivity());
		}

		/**
		 * 这里的String参数对应AsyncTask中的第一个参数 这里的String返回值对应AsyncTask的第三个参数
		 * 该方法并不运行在UI线程当中,主要用于异步操作,所以在该方法中不能对UI的空间进行设置和修改
		 * 但是可以调用publishProgress方法触发onProgressUpdate对UI进行操作
		 */
		@SuppressWarnings("unchecked")
		@Override
		protected Integer doInBackground(String... params) {

			personBeans = LocationApplication.getInstance().getContactList();
			String result = "";
			// 先将参数放入List,再对参数进行URL编码
			List nameValuePairs = new ArrayList();
			nameValuePairs
					.add(new BasicNameValuePair("tokenValue", tokenValue));

			try {
				if ("all".equals(params[0])) {
					if (personBeans == null) {
						result = new AsyncGET().getResponseInfo(
								API.getStaffInfo(), nameValuePairs);
						// System.out.println("--result--:" + result);
						if (!"".equals(result)
								&& !"[]".equals(result)
								&& !"Http error!".equals(noteUtil
										.getSubstring(result))) {
							personBeans = jsonUtil.parseJsonPersons(result);
							System.out
									.println("--员工数量--:" + personBeans.size());
							nameSort = new NameSort();
							Collections.sort(personBeans, nameSort);

						} else {
							personBeans = new ArrayList();
						}
						LocationApplication.getInstance().setContactList(
								personBeans);
					}
				}
			} catch (ClientProtocolException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
			return null;
		}

		/**
		 * 这里的Integer参数对应AsyncTask中的第二个参数 在doInBackground方法中,每次调用publishProgress
		 * 方法都会触发onProgressUpdate执行 onProgressUpdate是在UI线程中执行,所以可以对UI空间进行操作
		 */
		@Override
		protected void onProgressUpdate(Integer... values) {
			super.onProgressUpdate(values);
		}

		/**
		 * 这里的String参数对应AsyncTask中的第三个参数(也就是接收doInBackground的返回值)
		 * 在doInBackground方法执行结束后再运行,并且运行在UI线程中 可以对UI空间进行设置
		 */
		@Override
		protected void onPostExecute(Integer result) {
			super.onPostExecute(result);
			if (getActivity() != null && personBeans != null) {
				adapter = new ContactAdapter(getActivity(), personBeans, 0,
						null);
				contactLv.setAdapter(adapter);
				// 根据上次保存的index和偏移量恢复上次的位置
				contactLv.setSelectionFromTop(index, top);
			}
			myDialog.dismiss();
		}

	}

	@Override
	public void onMainAction(int todayYear, int todayMonth, int todayDay) {

	}

	@Override
	public void onCurrent(int todayYear, int todayMonth, int todayDay) {

	}

}

5.NameSort类实现Comparator,主要实现对通讯录的联系人首先按首字母进行排序,首字母相同则按姓名拼音排序,具体代码如下:
package com.util;

import java.util.Comparator;

import com.bean.note.PersonBean;

@SuppressWarnings("rawtypes")
public class NameSort implements Comparator {

	@Override
	public int compare(Object arg0, Object arg1) {

		PersonBean personBean01 = (PersonBean) arg0;
		PersonBean personBean02 = (PersonBean) arg1;
		if ("#".equals(personBean02.getHeader())) {
			return -1;
		} else if ("#".equals(personBean01.getHeader())) {
			return 1;
		} else {
			int flag = personBean01.getHeader().compareTo(
					personBean02.getHeader());
			if (flag == 0) {
				return personBean01.getPinyin().compareTo(
						personBean02.getPinyin());
			} else {
				return flag;
			}
		}
	}

}


你可能感兴趣的:(Android,Android项目实战基地)