这几天遇到一个项目需要向微信通讯录那样展示联系人,这里我做了一个简单的例子,希望可以帮助大家
先来看下界面的实现效果
上面的是在搜索框搜索时的结果,和点击后边的字母跳转到相应 的字母对应名字地方,并且显示你选择的字母
好了,现在我们来整理一下思路,怎么实现这中效果呢。
第一步,我们肯定是要有一个这样的界面
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="@color/yellow_page_search_bg"
android:paddingBottom="5dp"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:paddingTop="5dp" >
<com.mulu.widget.CustomEditText
android:id="@+id/school_friend_member_search_input"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:background="@drawable/bg_search_input"
android:drawableLeft="@drawable/ic_search"
android:drawablePadding="5dp"
android:drawableRight="@drawable/ic_edit_text_delbtn"
android:freezesText="true"
android:gravity="center_vertical"
android:hint="@string/school_friend_search_hint"
android:imeOptions="actionSearch"
android:singleLine="true"
android:textColor="@color/black"
android:textColorHint="@color/login_form_hint"
android:textSize="14sp" />
</RelativeLayout>
<TextView
android:layout_width="fill_parent"
android:layout_height="1px"
android:background="@drawable/bg_cut_line" />
<FrameLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content" >
<ListView
android:id="@+id/school_friend_member"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:cacheColorHint="@color/transparent"
android:divider="@drawable/bg_cut_line"
android:dividerHeight="1px"
android:fadingEdge="none"
android:listSelector="@color/transparent"
android:scrollbars="none" >
</ListView>
<TextView
android:id="@+id/school_friend_dialog"
android:layout_width="80.0dip"
android:layout_height="80.0dip"
android:layout_gravity="center"
android:background="@drawable/bg_show_head_toast"
android:gravity="center"
android:textColor="#ffffffff"
android:textSize="30.0dip"
android:visibility="invisible" />
<com.mulu.widget.SideBar
android:id="@+id/school_friend_sidrbar"
android:layout_width="30dp"
android:layout_height="fill_parent"
android:layout_gravity="right|center" />
</FrameLayout>
</LinearLayout>
这个界面引用了自定义的一些空间CustomEditText,SideBar,一个是最上面的搜索输入框,一个是要显示上图对应绿色的x那个布局,还有一些资源文件,我都放在相应的res下drawable-hdip这个包中,等会我会把相应的全部代码打包上传上来的,有需要的可以下载看看
下面我们来自定义我们需要的控件
package com.mulu.widget;
import android.content.Context;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.EditText;
/**
* 自定义文本输入框,增加清空按钮
*
* @author shaozc
*
*/
public class CustomEditText extends EditText {
private Drawable mLeft, mTop, mRight, mBottom;
private Rect mBounds;
public CustomEditText(Context context) {
super(context);
init();
}
public CustomEditText(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
public CustomEditText(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
setDrawable();
// 增加文本监听器.
addTextChangedListener(new TextWatcher() {
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void afterTextChanged(Editable s) {
setDrawable();
}
});
}
// 输入框右边的图标显示控制
private void setDrawable() {
if (length() == 0) {
setCompoundDrawables(mLeft, mTop, null, mBottom);
} else {
setCompoundDrawables(mLeft, mTop, mRight, mBottom);
}
}
@Override
public void setCompoundDrawables(Drawable left, Drawable top, Drawable right, Drawable bottom) {
if (mLeft == null) {
this.mLeft = left;
}
if (mTop == null) {
this.mTop = top;
}
if (mRight == null) {
this.mRight = right;
}
if (mBottom == null) {
this.mBottom = bottom;
}
super.setCompoundDrawables(left, top, right, bottom);
}
// 输入事件处理
@Override
public boolean onTouchEvent(MotionEvent event) {
if (mRight != null && event.getAction() == MotionEvent.ACTION_UP) {
this.mBounds = mRight.getBounds();
mRight.getIntrinsicWidth();
int eventX = (int) event.getX();
int width = mBounds.width();
int right = getRight();
int left = getLeft();
if (eventX > (right - width * 2 - left)) {
setText("");
event.setAction(MotionEvent.ACTION_CANCEL);
}
}
return super.onTouchEvent(event);
}
@Override
protected void finalize() throws Throwable {
super.finalize();
this.mLeft = null;
this.mTop = null;
this.mRight = null;
this.mBottom = null;
this.mBounds = null;
}
}
接下来是右边的字母布局控件
package com.mulu.widget;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.drawable.ColorDrawable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.TextView;
import com.mulu.activity.R;
public class SideBar extends View {
// 触摸事件
private OnTouchingLetterChangedListener onTouchingLetterChangedListener;
// 26个字母
public static String[] b = { "☆", "#", "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" };
private int choose = -1;// 选中
private Paint paint = new Paint();
private TextView mTextDialog;
public void setTextView(TextView mTextDialog) {
this.mTextDialog = mTextDialog;
}
public SideBar(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public SideBar(Context context, AttributeSet attrs) {
super(context, attrs);
}
public SideBar(Context context) {
super(context);
}
/**
* 重写这个方法
*/
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// 获取焦点改变背景颜色.
int height = getHeight();// 获取对应高度
int width = getWidth(); // 获取对应宽度
int singleHeight = height / b.length;// 获取每一个字母的高度
for (int i = 0; i < b.length; i++) {
if (!isInEditMode()) {
paint.setColor(Color.parseColor("#838383"));
}
paint.setAntiAlias(true);
paint.setTextSize(20);
// 选中的状态
if (i == choose) {
paint.setColor(getResources().getColor(R.color.yellow_light));
paint.setFakeBoldText(true);
}
// x坐标等于中间-字符串宽度的一半.
float xPos = width / 2 - paint.measureText(b[i]) / 2;
float yPos = singleHeight * i + singleHeight;
canvas.drawText(b[i], xPos, yPos, paint);
paint.reset();// 重置画笔
}
}
@SuppressWarnings("deprecation")
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
final int action = event.getAction();
final float y = event.getY();// 点击y坐标
final int oldChoose = choose;
final OnTouchingLetterChangedListener listener = onTouchingLetterChangedListener;
final int c = (int) (y / getHeight() * b.length);// 点击y坐标所占总高度的比例*b数组的长度就等于点击b中的个数.
switch (action) {
case MotionEvent.ACTION_UP:
setBackgroundDrawable(new ColorDrawable(0x00000000));
choose = -1;//
invalidate();
if (mTextDialog != null) {
mTextDialog.setVisibility(View.INVISIBLE);
}
break;
default:
if (oldChoose != c) {
if (c >= 0 && c < b.length) {
if (listener != null) {
listener.onTouchingLetterChanged(b[c]);
}
if (mTextDialog != null) {
mTextDialog.setText(b[c]);
mTextDialog.setVisibility(View.VISIBLE);
}
choose = c;
invalidate();
}
}
break;
}
return true;
}
/**
* 向外公开的方法
*
* @param onTouchingLetterChangedListener
*/
public void setOnTouchingLetterChangedListener(OnTouchingLetterChangedListener onTouchingLetterChangedListener) {
this.onTouchingLetterChangedListener = onTouchingLetterChangedListener;
}
/**
* 接口
*
* @author coder
*
*/
public interface OnTouchingLetterChangedListener {
public void onTouchingLetterChanged(String s);
}
}
再次说明一边,需要的资源文件都是放在res下drawable -hdp里面的
下面我们就来实现功能,那么这个时候我们还需要什么呢,我们还需要一个dto,还有一个拼音库的jar包,jar包我也放在我的项目源代码里了,需要的一会自己下载完成的代码,这是我的项目文件存放位置
dto
package com.mulu.dto;
public class PersonDto {
private Integer userId;// 用户ID
private String name;// 姓名
private String head;// 头像
private String utype;// 用户类型
private String sortLetters; // 显示数据拼音的首字母
private String suoxie;// 姓名缩写
private String signature;// 个性签名
public final Integer getUserId() {
return userId;
}
public final void setUserId(Integer userId) {
this.userId = userId;
}
public final String getName() {
return name;
}
public final void setName(String name) {
this.name = name;
}
public final String getHead() {
return head;
}
public final void setHead(String head) {
this.head = head;
}
public final String getUtype() {
return utype;
}
public final void setUtype(String utype) {
this.utype = utype;
}
public final String getSortLetters() {
return sortLetters;
}
public final void setSortLetters(String sortLetters) {
this.sortLetters = sortLetters;
}
public final String getSuoxie() {
return suoxie;
}
public final void setSuoxie(String suoxie) {
this.suoxie = suoxie;
}
public final String getSignature() {
return signature;
}
public final void setSignature(String signature) {
this.signature = signature;
}
}
下面来看一下主文件中的代码吧
package com.mulu.activity;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import android.app.Activity;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.TextView;
import com.mulu.adapter.SchoolFriendMemberListAdapter;
import com.mulu.dto.PersonDto;
import com.mulu.widget.CharacterParser;
import com.mulu.widget.PinyinComparator;
import com.mulu.widget.SideBar;
public class MainActivity extends Activity implements SideBar.OnTouchingLetterChangedListener, TextWatcher {
private SideBar mSideBar;
private TextView mDialog;
private ListView mListView;
private EditText mSearchInput;
private CharacterParser characterParser;// 汉字转拼音
private PinyinComparator pinyinComparator;// 根据拼音来排列ListView里面的数据类
private List<PersonDto> sortDataList = new ArrayList<PersonDto>();
private SchoolFriendMemberListAdapter mAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mListView = (ListView) findViewById(R.id.school_friend_member);
mSideBar = (SideBar) findViewById(R.id.school_friend_sidrbar);
mDialog = (TextView) findViewById(R.id.school_friend_dialog);
mSearchInput = (EditText) findViewById(R.id.school_friend_member_search_input);
mSideBar.setTextView(mDialog);
mSideBar.setOnTouchingLetterChangedListener(this);
initData();
}
/**
* 初始化数据
*/
private void initData() {
// 实例化汉字转拼音类
characterParser = CharacterParser.getInstance();
pinyinComparator = new PinyinComparator();
PersonDto cuser1 = new PersonDto();
cuser1.setName("阿东");
cuser1.setSortLetters("a");
PersonDto cuser2 = new PersonDto();
cuser2.setName("贝贝");
cuser2.setSortLetters("b");
PersonDto cuser3 = new PersonDto();
cuser3.setName("西西");
cuser3.setSortLetters("x");
PersonDto cuser4 = new PersonDto();
cuser4.setName("楠楠");
cuser4.setSortLetters("n");
PersonDto cuser5 = new PersonDto();
cuser5.setName("君君");
cuser5.setSortLetters("j");
PersonDto cuser6 = new PersonDto();
cuser6.setName("陈诚");
cuser6.setSortLetters("c");
PersonDto cuser7 = new PersonDto();
cuser7.setName("美美");
cuser7.setSortLetters("m");
PersonDto cuser8 = new PersonDto();
cuser8.setName("花园");
cuser8.setSortLetters("h");
PersonDto cuser9 = new PersonDto();
cuser9.setName("天天");
cuser9.setSortLetters("t");
PersonDto cuser10 = new PersonDto();
cuser10.setName("八戒");
cuser10.setSortLetters("b");
sortDataList.add(cuser1);
sortDataList.add(cuser2);
sortDataList.add(cuser3);
sortDataList.add(cuser4);
sortDataList.add(cuser5);
sortDataList.add(cuser6);
sortDataList.add(cuser7);
sortDataList.add(cuser8);
sortDataList.add(cuser9);
sortDataList.add(cuser10);
fillData(sortDataList);
// 根据a-z进行排序源数据
Collections.sort(sortDataList, pinyinComparator);
mAdapter = new SchoolFriendMemberListAdapter(this, sortDataList);
mListView.setAdapter(mAdapter);
mSearchInput.addTextChangedListener(this);
}
@Override
public void onTouchingLetterChanged(String s) {
int position = 0;
// 该字母首次出现的位置
if(mAdapter != null){
position = mAdapter.getPositionForSection(s.charAt(0));
}
if (position != -1) {
mListView.setSelection(position);
}
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
// 当输入框里面的值为空,更新为原来的列表,否则为过滤数据列表
filterData(s.toString(), sortDataList);
}
@Override
public void afterTextChanged(Editable s) {
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
/**
* 根据输入框中的值来过滤数据并更新ListView
*
* @param filterStr
*/
private void filterData(String filterStr, List<PersonDto> list) {
List<PersonDto> filterDateList = new ArrayList<PersonDto>();
if (TextUtils.isEmpty(filterStr)) {
filterDateList = list;
} else {
filterDateList.clear();
for (PersonDto sortModel : list) {
String name = sortModel.getName();
String suoxie = sortModel.getSuoxie();
if (name.indexOf(filterStr.toString()) != -1 || suoxie.indexOf(filterStr.toString()) != -1 || characterParser.getSelling(name).startsWith(filterStr.toString())) {
filterDateList.add(sortModel);
}
}
}
// 根据a-z进行排序
Collections.sort(filterDateList, pinyinComparator);
mAdapter.updateListView(filterDateList);
}
/**
* 填充数据
*
* @param list
*/
private void fillData(List<PersonDto> list) {
for (PersonDto cUserInfoDto : list) {
if (cUserInfoDto != null && cUserInfoDto.getName() != null) {
String pinyin = characterParser.getSelling(cUserInfoDto.getName());
String suoxie = CharacterParser.getFirstSpell(cUserInfoDto.getName());
cUserInfoDto.setSuoxie(suoxie);
String sortString = pinyin.substring(0, 1).toUpperCase();
if ("1".equals(cUserInfoDto.getUtype())) {// 判断是否是管理员
cUserInfoDto.setSortLetters("☆");
} else if (sortString.matches("[A-Z]")) {// 正则表达式,判断首字母是否是英文字母
cUserInfoDto.setSortLetters(sortString);
} else {
cUserInfoDto.setSortLetters("#");
}
}
}
}
}
这里还需要一个展示listView的一个适配器,我把它单独拿出来了,放在adapter包中的
package com.mulu.adapter;
import android.app.Activity;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.*;
import com.mulu.dto.PersonDto;
import com.mulu.activity.R;
import java.util.List;
/**
* 成员列表适配器
*/
public class SchoolFriendMemberListAdapter extends BaseAdapter implements SectionIndexer {
private LayoutInflater inflater;
private Activity mActivity;
private List<PersonDto> list;
public SchoolFriendMemberListAdapter(Activity mActivity, List<PersonDto> list) {
this.mActivity = mActivity;
this.list = list;
}
/**
* 当ListView数据发生变化时,调用此方法来更新ListView
*
* @param list
*/
public void updateListView(List<PersonDto> list) {
this.list = list;
notifyDataSetChanged();
}
@Override
public int getCount() {
return list.size();
}
@Override
public Object getItem(int position) {
return null;
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
if (convertView == null) {
inflater = (LayoutInflater) mActivity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.items_person_list, null);
holder = new ViewHolder();
holder.ivHead = (ImageView) convertView.findViewById(R.id.head);
holder.tvTitle = (TextView) convertView.findViewById(R.id.title);
holder.tvLetter = (TextView) convertView.findViewById(R.id.catalog);
holder.tvLine = (TextView) convertView.findViewById(R.id.line);
holder.tvContent = (LinearLayout) convertView.findViewById(R.id.content);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
final PersonDto dto = list.get(position);
if (dto != null) {
// 根据position获取分类的首字母的Char ascii值
int section = getSectionForPosition(position);
// 如果当前位置等于该分类首字母的Char的位置 ,则认为是第一次出现
if (position == getPositionForSection(section)) {
holder.tvLetter.setVisibility(View.VISIBLE);
holder.tvLetter.setText("☆".equals(dto.getSortLetters()) ? dto.getSortLetters() + "(管理员)" : dto.getSortLetters());
holder.tvLine.setVisibility(View.VISIBLE);
} else {
holder.tvLetter.setVisibility(View.GONE);
holder.tvLine.setVisibility(View.GONE);
}
holder.tvTitle.setText(dto.getName());
}
return convertView;
}
class ViewHolder {
ImageView ivHead;
TextView tvLetter;
TextView tvTitle;
TextView tvLine;
LinearLayout tvContent;
}
/**
* 根据ListView的当前位置获取分类的首字母的Char ascii值
*/
public int getSectionForPosition(int position) {
return list.get(position).getSortLetters().charAt(0);
}
/**
* 根据分类的首字母的Char ascii值获取其第一次出现该首字母的位置
*/
public int getPositionForSection(int section) {
for (int i = 0; i < getCount(); i++) {
String sortStr = list.get(i).getSortLetters();
char firstChar = sortStr.toUpperCase().charAt(0);
if (firstChar == section) {
return i;
}
}
return -1;
}
@Override
public Object[] getSections() {
return null;
}
}
还需要一个PinyinComparator实现Comparator的类
package com.mulu.widget;
import com.mulu.dto.PersonDto;
import java.util.Comparator;
public class PinyinComparator implements Comparator<PersonDto> {
@Override
public int compare(PersonDto o1, PersonDto o2) {
if (o1.getSortLetters().equals("☆")) {
return -1;
} else if (o2.getSortLetters().equals("☆")) {
return 1;
} else if (o1.getSortLetters().equals("#")) {
return -1;
} else if (o2.getSortLetters().equals("#")) {
return 1;
} else {
return o1.getSortLetters().compareTo(o2.getSortLetters());
}
}
}
好了基本的代码也就这些了,下面是我完整代码的地址,欢迎下载http://download.csdn.net/detail/shaozucheng/8204905