最近在做的项目中有个通讯录功能,里面实现了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);
}
}
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) {
}
}
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;
}
}
}
}