联系人的侧边字母索引ListView 将手机通讯录姓名通过首字母排序。
2015-12-08 17:59
537 查看
packagecom.lixu.letterlistview;
importjava.util.ArrayList;
importjava.util.List;
importorg.apache.http.NameValuePair;
importorg.apache.http.message.BasicNameValuePair;
importcom.lixu.letterlistview.letter.LetterBaseListAdapter;
importcom.lixu.letterlistview.letter.LetterListView;
importcom.lixu.lianxirenlist.R;
importandroid.app.Activity;
importandroid.content.ContentResolver;
importandroid.database.Cursor;
importandroid.graphics.Color;
importandroid.net.Uri;
importandroid.os.Bundle;
importandroid.view.Gravity;
importandroid.view.View;
importandroid.view.ViewGroup;
importandroid.widget.TextView;
publicclassMainActivityextendsActivity{
privateArrayList<String>dataArray;
@Override
protectedvoidonCreate(BundlesavedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//通过获取手机通讯录的姓名
dataArray=newArrayList<String>();
Uriuri=Uri.parse("content://com.android.contacts/contacts");
ContentResolverresolver=this.getContentResolver();
//给query传递一个SORT_KEY_PRIMARY,让ContentResolver将获得的数据按照联系人名字首字母排序
Cursorcursor=resolver.query(uri,null,null,null,
android.provider.ContactsContract.Contacts.SORT_KEY_PRIMARY);
while(cursor.moveToNext())
{
//联系人的id
Stringid=cursor.getString(cursor.getColumnIndex(android.provider.ContactsContract.Contacts._ID));
//将联系人按姓名首字母分组
Stringsort_key_primary=cursor
.getString(cursor.getColumnIndex(android.provider.ContactsContract.Contacts.SORT_KEY_PRIMARY));
//获取联系人的名字
Stringname=cursor
.getString(cursor.getColumnIndex(android.provider.ContactsContract.Contacts.DISPLAY_NAME));
dataArray.add(name);
}
LetterListViewletterListView=(LetterListView)findViewById(R.id.letterListView);
letterListView.setAdapter(newTestAdapter());
}
/**
*这里使用一个简单的NameValuePair对象,做为测试
*
*@Title:
*@Description:
*@Author:Justlcw
*@Since:2014-5-13
*@Version:
*/
classTestAdapterextendsLetterBaseListAdapter<NameValuePair>{
/**字母对应的key,因为字母是要插入到列表中的,为了区别,所有字母的item都使用同一的key.**/
privatestaticfinalStringLETTER_KEY="letter";
publicTestAdapter(){
super();
List<NameValuePair>dataList=newArrayList<NameValuePair>();
for(inti=0;i<dataArray.size();i++){
NameValuePairpair=newBasicNameValuePair(String.valueOf(i),dataArray.get(i));
dataList.add(pair);
}
setContainerList(dataList);
}
@Override
publicObjectgetItem(intposition){
returnlist.get(position);
}
@Override
publiclonggetItemId(intposition){
returnposition;
}
@Override
publicStringgetItemString(NameValuePairt){
returnt.getValue();
}
@Override
publicNameValuePaircreate(charletter){
returnnewBasicNameValuePair(LETTER_KEY,String.valueOf(letter));
}
@Override
publicbooleanisLetter(NameValuePairt){
//判断是不是字母行,通过key比较,这里是NameValuePair对象,其他对象,就由你自己决定怎么判断了.
returnt.getName().equals(LETTER_KEY);
}
@Override
publicViewgetLetterView(intposition,ViewconvertView,ViewGroupparent){
//这里是字母的item界面设置.
if(convertView==null){
convertView=newTextView(MainActivity.this);
((TextView)convertView).setGravity(Gravity.CENTER_VERTICAL);
convertView.setBackgroundColor(getResources().getColor(android.R.color.white));
}
((TextView)convertView).setText(list.get(position).getValue());
((TextView)convertView).setBackgroundColor(Color.GREEN);
((TextView)convertView).setTextSize(25);
returnconvertView;
}
@Override
publicViewgetContainerView(intposition,ViewconvertView,ViewGroupparent){
//这里是其他正常数据的item界面设置.
if(convertView==null){
convertView=newTextView(MainActivity.this);
((TextView)convertView).setGravity(Gravity.CENTER_VERTICAL);
}
((TextView)convertView).setText(list.get(position).getValue());
((TextView)convertView).setBackgroundColor(Color.YELLOW);
((TextView)convertView).setTextSize(20);
returnconvertView;
}
}
}
packagecom.lixu.letterlistview.letter;
importandroid.widget.BaseAdapter;
/**
*带有侧边字母列表的listView适配器
*
*@Title:
*@Description:
*@Author:Justlcw
*@Since:2014-5-8
*@Version:
*/
publicabstractclassLetterBaseAdapterextendsBaseAdapter
{
/**字母表头部**/
protectedstaticfinalcharHEADER='+';
/**字母表尾部**/
protectedstaticfinalcharFOOTER='#';
/**
*是否需要隐藏没有匹配到的字母
*
*@returntrue隐藏,false不隐藏
*@Description:
*@AuthorJustlcw
*@Date2014-5-8
*/
publicabstractbooleanhideLetterNotMatch();
/**
*获取字母对应的位置
*
*@returnposition
*@Description:
*@AuthorJustlcw
*@Date2014-5-8
*/
publicabstractintgetIndex(charletter);
}
packagecom.lixu.letterlistview.letter;
importjava.util.ArrayList;
importjava.util.HashMap;
importjava.util.List;
importjava.util.Map;
importandroid.text.TextUtils;
importandroid.util.Log;
importandroid.view.View;
importandroid.view.ViewGroup;
/**
*通用带有字母列表的泛型对象adapter
*
*@Title:
*@Description:
*@Author:Justlcw
*@Since:2014-5-9
*@Version:
*/
publicabstractclassLetterBaseListAdapter<T>extendsLetterBaseAdapter{
/**logtag.**/
privatestaticfinalStringTAG="LetterBaseListAdapter";
/**默认错误头部字母.**/
privatestaticfinalcharERROR_LETTER='';
/**viewtype的类型总数**/
privatestaticfinalintTYPE_COUNT=2;
/**字母类型**/
privatestaticfinalintTYPE_LETTER=0;
/**实体类型**/
privatestaticfinalintTYPE_CONTAINER=1;
/**添加字母之后的list**/
protectedfinalList<T>list;
/**字母头位置标示map**/
privatefinalMap<Character,Integer>letterMap;
/**
*构造方法
*/
publicLetterBaseListAdapter(){
list=newArrayList<T>();
letterMap=newHashMap<Character,Integer>();
}
/**
*构造方法
*
*@paramdataArray
*内容数组
*/
publicLetterBaseListAdapter(T[]dataArray){
this();
setContainerList(dataArray);
}
/**
*构造方法
*
*@paramdataList
*内容列表
*/
publicLetterBaseListAdapter(List<T>dataList){
this();
setContainerList(dataList);
}
/**
*设置主体内容
*
*@paramdataArray
*实体数组
*@Description:
*@AuthorJustlcw
*@Date2014-5-9
*/
protectedfinalvoidsetContainerList(T[]dataArray){
if(!list.isEmpty()){
list.clear();
}
if(!letterMap.isEmpty()){
letterMap.clear();
}
charletter=ERROR_LETTER;
intindex=0;
for(inti=0;i<dataArray.length;i++){
Tt=dataArray[i];
charl=getHeaderLetter(t);
if(letter!=l&&l!=ERROR_LETTER){
//如果发现这个字母没有添加过,更新一下标示
letter=l;
//创建一个T类型的字母头放进去
Ttl=create(letter);
if(tl!=null){
//如果创建成功,则插入到列表中
list.add(tl);
}
//存放最新字母对应的位置
letterMap.put(letter,index);
index++;
}
//添加原本的填充实体项
list.add(t);
index++;
}
}
/**
*设置主体内容.
*
*@paramdataList
*实体列表
*@Description:
*@AuthorJustlcw
*@Date2014-5-9
*/
protectedfinalvoidsetContainerList(List<T>dataList){
if(!list.isEmpty()){
list.clear();
}
if(!letterMap.isEmpty()){
letterMap.clear();
}
charletter='';
intindex=0;
for(inti=0;i<dataList.size();i++){
Tt=dataList.get(i);
charl=getHeaderLetter(t);
if(letter!=l&&l!=ERROR_LETTER){
//如果发现这个字母没有添加过,更新一下标示
letter=l;
//创建一个T类型的字母头放进去
Ttl=create(letter);
if(tl!=null){
//如果创建成功,则插入到列表中
list.add(tl);
}
//存放最新字母对应的位置
letterMap.put(letter,index);
index++;
}
//添加原本的填充实体项
list.add(t);
index++;
}
}
/**
*@paramt
*<实体item对象>
*
*@return<实体item对象>首字母,获取失败返回{@link#ERROR_LETTER}
*@Description:
*@AuthorJustlcw
*@Date2014-5-12
*/
privatechargetHeaderLetter(Tt){
//获取item对应的字符串
Stringstr=getItemString(t);
//如果为空,跳出继续
if(TextUtils.isEmpty(str)){
Log.e(TAG,"itemstringemptyin"+t.toString());
returnERROR_LETTER;
}
charl;
//获取第一个字母
charfirstChar=str.charAt(0);
if(firstChar==HEADER||firstChar==FOOTER||LetterUtil.isLetter(firstChar)){
l=firstChar;//如果是头,尾,字母,直接赋值
}else{
String[]letterArray=LetterUtil.getFirstPinyin(firstChar);
//如果是汉字,取拼音首字母
if(letterArray!=null&&letterArray.length>0){
l=letterArray[0].charAt(0);
}else{
//如果汉字转拼音失败了,跳过
Log.e(TAG,firstChar+"turntoletterfail,"+t.toString());
returnERROR_LETTER;
}
}
//如果是小写字母,转换为大写字母
if(l>='a'){
l=(char)(l-32);
}
returnl;
}
@Override
publicfinalintgetCount(){
returnlist.size();
}
@Override
publicfinalViewgetView(intposition,ViewconvertView,ViewGroupparent){
if(getItemViewType(position)==TYPE_LETTER){
returngetLetterView(position,convertView,parent);
}
returngetContainerView(position,convertView,parent);
}
@Override
publicfinalintgetItemViewType(intposition){
if(isLetter(list.get(position))){
returnTYPE_LETTER;
}
returnTYPE_CONTAINER;
}
@Override
publicfinalintgetViewTypeCount(){
returnTYPE_COUNT;
}
@Override
publicbooleanhideLetterNotMatch(){
returnfalse;
}
@Override
publicfinalintgetIndex(charletter){
Integerindex=letterMap.get(letter);
if(index==null){
return-1;
}
returnindex;
}
/**
*@paramT
*<实体item对象>
*
*@return<实体item对象>对应的String,用来获取<拼音首字母>
*@Description:
*@AuthorJustlcw
*@Date2014-5-9
*/
publicabstractStringgetItemString(Tt);
/**
*@paramletter
*<字母>
*
*@return根据<字母>创建一个<实体item对象>,用来显示<字母item>
*@Description:
*@AuthorJustlcw
*@Date2014-5-9
*/
publicabstractTcreate(charletter);
/**
*@paramt
*<实体item对象>
*
*@return根据<实体item对象>,判断是否是<字母item>
*@Description:
*@AuthorJustlcw
*@Date2014-5-9
*/
publicabstractbooleanisLetter(Tt);
/**
*返回<字母item>界面,其他的同
*<P>
*{@link#getView(int,View,ViewGroup)}
*
*@Description:
*@AuthorJustlcw
*@Date2014-5-9
*/
publicabstractViewgetLetterView(intposition,ViewconvertView,ViewGroupparent);
/**
*返回<实体item>界面,其他的同
*<P>
*{@link#getView(int,View,ViewGroup)}
*
*@Description:
*@AuthorJustlcw
*@Date2014-5-9
*/
publicabstractViewgetContainerView(intposition,ViewconvertView,ViewGroupparent);
}
packagecom.lixu.letterlistview.letter;
importjava.lang.ref.SoftReference;
importjava.util.ArrayList;
importjava.util.List;
importcom.lixu.lianxirenlist.R;
importandroid.content.Context;
importandroid.os.Handler;
importandroid.os.Message;
importandroid.util.AttributeSet;
importandroid.view.Gravity;
importandroid.view.LayoutInflater;
importandroid.view.MotionEvent;
importandroid.view.View;
importandroid.view.ViewGroup;
importandroid.widget.AbsListView;
importandroid.widget.BaseAdapter;
importandroid.widget.FrameLayout;
importandroid.widget.ListView;
importandroid.widget.TextView;
importandroid.widget.AdapterView.OnItemClickListener;
/**
*带有字母列表的listView
*
*@Title:
*@Description:
*@Author:Justlcw
*@Since:2014-5-7
*@Version:
*/
publicclassLetterListViewextendsFrameLayout{
/**隐藏字母消息**/
privatefinalintMSG_HIDE_LETTER=0x0;
/**字母列表的宽度**/
privatefinalintLETTER_LIST_VIEW_WIDTH=50;//TODO这里宽度写死了,按着一定的比例比较好
/**内容列表**/
privateListViewmListView;
/**内容列表适配器**/
privateLetterBaseAdaptermAdapter;
/**字母列表**/
privateListViewmLetterListView;
privateLetterAdaptermLetterAdapter;
privateTextViewmLetterTextView;
/**字母消息Handler**/
privateHandlermLetterhandler;
/**
*构造方法
*
*@paramcontext
*/
publicLetterListView(Contextcontext){
super(context);
initListView(context);
}
/**
*构造方法
*
*@paramcontext
*@paramattrs
*/
publicLetterListView(Contextcontext,AttributeSetattrs){
super(context,attrs);
initListView(context);
}
/**
*初始化内容列表字母列表
*
*@Description:
*@AuthorJustlcw
*@Date2014-5-7
*/
privatevoidinitListView(Contextcontext){
LayoutInflaterinflater=LayoutInflater.from(getContext());
//TODO这里添加内容列表,可以在这里对ListView进行一些你想要的设置
mListView=(ListView)inflater.inflate(R.layout.letter_list_container,null,false);
LayoutParamslp=newLayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT);
addView(mListView,lp);
//TODO这里添加字母列表,可以在这里对ListView进行一些你想要的设置
mLetterListView=(ListView)inflater.inflate(R.layout.letter_list_letter,null,false);
mLetterListView.setOnTouchListener(mLetterOnTouchListener);
LayoutParamsletterListLp=newLayoutParams(LETTER_LIST_VIEW_WIDTH,LayoutParams.MATCH_PARENT,Gravity.RIGHT);
addView(mLetterListView,letterListLp);
//TODO这里对显示的字母进行设置
mLetterTextView=(TextView)inflater.inflate(R.layout.letter_list_position,null,false);
LayoutParamsletterLp=newLayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT,Gravity.CENTER);
addView(mLetterTextView,letterLp);
mLetterTextView.setVisibility(View.INVISIBLE);
//初始化letter消息发送者
mLetterhandler=newLetterHandler(this);
}
/**
*设置内容列表适配器
*
*@paramadapter
*{@linkLetterBaseAdapter}
*@Description:
*@AuthorJustlcw
*@Date2014-5-7
*/
publicvoidsetAdapter(LetterBaseAdapteradapter){
if(adapter!=null){
mAdapter=adapter;
mListView.setAdapter(mAdapter);
}
}
/**
*{@linkAbsListView#setOnItemClickListener(OnItemClickListener)}
*
*@Description:
*@AuthorJustlcw
*@Date2014-5-14
*/
publicvoidsetOnItemClickListener(OnItemClickListeneronItemClickListener){
mListView.setOnItemClickListener(onItemClickListener);
}
@Override
protectedvoidonSizeChanged(intw,inth,intoldw,intoldh){
super.onSizeChanged(w,h,oldw,oldh);
mLetterAdapter=newLetterAdapter(h-getPaddingTop()-getPaddingBottom());
mLetterListView.setAdapter(mLetterAdapter);
}
/**
*显示字母
*
*@Description:
*@AuthorJustlcw
*@Date2014-5-8
*/
privatevoidshowLetter(Stringletter){
if(mLetterTextView.getVisibility()!=View.VISIBLE){
mLetterTextView.setVisibility(View.VISIBLE);
mLetterListView.setBackgroundResource(android.R.color.darker_gray);
}
mLetterTextView.setText(letter);
mLetterhandler.removeMessages(MSG_HIDE_LETTER);
mLetterhandler.sendEmptyMessageDelayed(MSG_HIDE_LETTER,500);
}
/**
*处理消息{@linkLetterHandler#handleMessage(Message)}
*
*@parammsg
*消息
*@Description:
*@AuthorJustlcw
*@Date2014-5-8
*/
privatevoidhandleLetterMessage(Messagemsg){
mLetterTextView.setVisibility(View.INVISIBLE);
mLetterListView.setBackgroundResource(android.R.color.white);
}
/**字母栏touch事件**/
privateView.OnTouchListenermLetterOnTouchListener=newView.OnTouchListener(){
@Override
publicbooleanonTouch(Viewv,MotionEventevent){
intheight=(int)event.getY()-v.getTop();
intposition=mLetterAdapter.getTouchPoistion(height);
if(position>=0){
charletter=(Character)mLetterAdapter.getItem(position);
//显示字母
showLetter(String.valueOf(letter));
//显示到字母对应的位置
intselect=mAdapter.getIndex(letter);
if(select>=0){
mListView.setSelection(select);
}
returntrue;
}
returnfalse;
}
};
/**
*字母列表设配器
*
*@Title:
*@Description:
*@Author:Justlcw
*@Since:2014-5-7
*@Version:
*/
privateclassLetterAdapterextendsBaseAdapter{
/**字母表**/
privatestaticfinalStringLETTER_STR="+ABCDEFGHIJKLMNOPQRSTUVWXYZ#";
/**最终显示的字母array**/
privatechar[]letterArray;
/**每个字母的高度**/
privateintitemHeight;
/**
*构造方法
*
*@paramheight
*viewheight
*/
publicLetterAdapter(intheight){
if(mAdapter.hideLetterNotMatch()){
List<Character>list=newArrayList<Character>();
char[]allArray=LETTER_STR.toCharArray();
for(inti=0;i<allArray.length;i++){
charletter=allArray[i];
intposition=mAdapter.getIndex(letter);
if(position>=0){
list.add(letter);
}
}
letterArray=newchar[list.size()];
for(inti=0;i<list.size();i++){
letterArray[i]=list.get(i);
}
list.clear();
list=null;
}else{
letterArray=LETTER_STR.toCharArray();
}
itemHeight=height/letterArray.length;
}
@Override
publicintgetCount(){
returnletterArray.length;
}
@Override
publicObjectgetItem(intposition){
returnletterArray[position];
}
@Override
publiclonggetItemId(intposition){
returnposition;
}
@Override
publicViewgetView(intposition,ViewconvertView,ViewGroupparent){
if(convertView==null){
convertView=newTextView(getContext());
((TextView)convertView).setTextColor(getResources().getColor(android.R.color.black));
((TextView)convertView).setGravity(Gravity.CENTER);
AbsListView.LayoutParamslp=newAbsListView.LayoutParams(AbsListView.LayoutParams.MATCH_PARENT,
itemHeight);
convertView.setLayoutParams(lp);
}
((TextView)convertView).setText(String.valueOf(letterArray[position]));
returnconvertView;
}
/**
*获取touch的位置
*
*@returnposition
*@Description:
*@AuthorJustlcw
*@Date2014-5-8
*/
publicintgetTouchPoistion(inttouchHeight){
intposition=touchHeight/itemHeight;
if(position>=0&&position<getCount()){
returnposition;
}
return-1;
}
}
/**
*处理字母显示的handler.
*
*@Title:
*@Description:
*@Author:Justlcw
*@Since:2014-5-8
*@Version:
*/
privatestaticclassLetterHandlerextendsHandler{
/**弱引用{@linkLetterListView}**/
privateSoftReference<LetterListView>srLetterListView;
/**
*构造方法
*
*@paramletterListView
*{@linkLetterListView}
*/
publicLetterHandler(LetterListViewletterListView){
srLetterListView=newSoftReference<LetterListView>(letterListView);
}
@Override
publicvoidhandleMessage(Messagemsg){
LetterListViewletterListView=srLetterListView.get();
//如果view没有被销毁掉,交给view处理这个消息
if(letterListView!=null){
letterListView.handleLetterMessage(msg);
}
}
}
}
packagecom.lixu.letterlistview.letter;
importnet.sourceforge.pinyin4j.PinyinHelper;
/**
*字母工具类
*@Title:
*@Description:
*@Author:Justlcw
*@Since:2014-5-8
*@Version:
*/
publicclassLetterUtil
{
/**
*@paramchinese一个汉字
*@return拼音首字母
*@Description:
*@AuthorJustlcw
*@Date2014-5-8
*/
publicstaticString[]getFirstPinyin(charchinese)
{
returnPinyinHelper.toHanyuPinyinStringArray(chinese);
}
/**
*是否是字母
*
*@returntrue字母,false非字母
*@Description:
*@AuthorJustlcw
*@Date2014-5-8
*/
publicstaticbooleanisLetter(charc)
{
return(c>=65&&c<=90)||(c>=97&&c<=112);
}
}
xml文件:
<RelativeLayoutxmlns: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">
<com.lixu.letterlistview.letter.LetterListView
android:id="@+id/letterListView"
android:layout_width="match_parent"
android:layout_height="match_parent">
</com.lixu.letterlistview.letter.LetterListView>
</RelativeLayout>
<?xmlversion="1.0"encoding="utf-8"?>
<ListViewxmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:cacheColorHint="@android:color/transparent"
android:divider="@android:color/transparent"
android:dividerHeight="0dp"
android:scrollbars="none"/>
<?xmlversion="1.0"encoding="utf-8"?>
<ListViewxmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#f44336"
android:cacheColorHint="@android:color/transparent"
android:divider="@android:color/transparent"
android:dividerHeight="0dp"
android:scrollbars="none"/>
<?xmlversion="1.0"encoding="utf-8"?>
<TextViewxmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#f44336"
android:gravity="center"
android:maxWidth="70dip"
android:minWidth="70dip"
android:padding="10dip"
android:textColor="@android:color/black"
android:textSize="50sp"/>
运行效果图:
相关文章推荐
- 云·端·创变,AppCan移动云大会圆满落幕
- 7.30
- php字符串编码的转换
- 网络程序开发实验报告
- NSMutableArray (可变数组增、删、改、查)
- C++学习_继承覆盖重载
- C++学习随笔
- java 类加载顺序 静态变量初始化顺序,何时触发类加载
- C++学习之继承篇
- ViewPager和Tabhost结合,可滑动的tabhost
- java读取properties配置文件
- loadlibrary返回 NULL , 错误码值126
- android studio从布局文件中提取style
- POI+EL表达式 Excel导出功能
- C#使用参数数组
- SVN服务器搭建和使用(三)
- JavaScript 语法总结3
- 【My First Blog】评近期国产烂片-《何以笙箫默》
- Linux基础网络设置
- userAgent,JS用户代理检测——判断浏览器内核、浏览器、浏览器平台、windows操作系统版本、移动设备、游戏系统