Android手机联系人快速索引(手机通讯录)

时间:2022-09-20 22:25:46

最近需要实现一个手机通讯录的快速索引功能。根据姓名首字母快速索引功能。下面是一个手机联系人快速索引的效果,总体来说代码不算难,拼音转换的地方略有复杂。下面上源码:源码中有注释。

下面是效果图:

Android手机联系人快速索引(手机通讯录)

mainactivity:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
import java.util.arraylist;
import java.util.collections;
import java.util.list;
import android.app.activity;
import android.os.bundle;
import android.os.handler;
import android.view.view;
import android.view.viewgroup;
import android.widget.baseadapter;
import android.widget.listview;
import android.widget.textview;
/**
 * 这里是主布局
 * @author lxd
 *
 */
public class mainactivity extends activity {
 private listview lv_main;
 private friendadapter adapter;
 private list<friend> data = new arraylist<friend>();
 private quickindexview qiv_main;
 private textview tv_main_word;
 private handler handler = new handler(){
 public void handlemessage(android.os.message msg) {
  //隐藏word
  tv_main_word.setvisibility(view.gone);
 }
 };
 @override
 protected void oncreate(bundle savedinstancestate) {
 super.oncreate(savedinstancestate);
 setcontentview(r.layout.activity_main);
 lv_main = (listview) findviewbyid(r.id.lv_main);
 qiv_main = (quickindexview) findviewbyid(r.id.qiv_main);
 tv_main_word = (textview) findviewbyid(r.id.tv_main_word);
 //设置监听
 qiv_main.setonindexchangedlistener(new quickindexview.onindexchangedlistener() {
  @override
  public void onindexchanged(string word) {
  tv_main_word.settext(word);
  tv_main_word.setvisibility(view.visible);
  //handler.removemessages(1);
  //移除未处理的消息
  handler.removecallbacksandmessages(null);
  //发延迟消息
  handler.sendemptymessagedelayed(1, 2000);
  //滑动listview
  //查找对应的item
  for(int i=0;i<data.size();i++) {
   string fword = data.get(i).getpinyin().substring(0, 1);
   if(word.equals(fword)) {
   lv_main.setselection(i);
   return;
   }
  }
  }
  @override
  public void onup() {
  //tv_main_word.setvisibility(view.gone);
  }
 });
 //显示列表
 adapter = new friendadapter();
 initdata();
 lv_main.setadapter(adapter);
 //lv_main.setselection(5);
 }
 private void initdata() {
 data.add(new friend("张三"));
 data.add(new friend("杨九"));
 data.add(new friend("胡继群"));
 data.add(new friend("刘畅"));
 data.add(new friend("钟泽兴"));
 data.add(new friend("尹革新"));
 data.add(new friend("安传鑫"));
 data.add(new friend("张骞壬"));
 data.add(new friend("温松"));
 data.add(new friend("李凤秋"));
 data.add(new friend("刘甫"));
 data.add(new friend("娄全超"));
 data.add(new friend("张猛"));
 data.add(new friend("王英杰"));
 data.add(new friend("李振南"));
 data.add(new friend("孙仁政"));
 data.add(new friend("唐春雷"));
 data.add(new friend("牛鹏伟"));
 data.add(new friend("姜宇航"));
 data.add(new friend("刘挺"));
 data.add(new friend("张洪瑞"));
 data.add(new friend("张建忠"));
 data.add(new friend("侯亚帅"));
 data.add(new friend("刘帅"));
 data.add(new friend("乔竞飞"));
 data.add(new friend("徐雨健"));
 data.add(new friend("吴亮"));
 data.add(new friend("王兆霖"));
 data.add(new friend("阿三"));
 collections.sort(data);
 }
 class friendadapter extends baseadapter {
 @override
 public int getcount() {
  return data.size();
 }
 @override
 public object getitem(int position) {
  return data.get(position);
 }
 @override
 public long getitemid(int position) {
  return 0;
 }
 @override
 public view getview(int position, view convertview, viewgroup parent) {
  viewholder holder = null;
  if(convertview==null) {
  holder = new viewholder();
  convertview = view.inflate(mainactivity.this, r.layout.item_main, null);
  holder.wordtv = (textview) convertview.findviewbyid(r.id.tv_item_word);
  holder.nametv = (textview) convertview.findviewbyid(r.id.tv_item_name);
  convertview.settag(holder);//***********?
  } else {
  holder = (viewholder) convertview.gettag();
  }
  friend friend = data.get(position);
  string word = friend.getpinyin().substring(0, 1);
  holder.wordtv.settext(word);
  holder.nametv.settext(friend.getname());
  //下标为0的显示
  if(position==0) {
  holder.wordtv.setvisibility(view.visible);
  } else {
  //取出上一个friend, 并得到的第一个word
  string preword = data.get(position-1).getpinyin().substring(0, 1);
  //判断是否于当前行的word是否相同
   //如果相同, 隐藏
  if(word.equals(preword)) {
   holder.wordtv.setvisibility(view.gone);
  } else {
   //如果不同, 显示
   holder.wordtv.setvisibility(view.visible);
  }
  }
  return convertview;
 }
 class viewholder {
  public textview wordtv;
  public textview nametv;
 }
 }
}

主布局:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<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="${relativepackage}.${activityclass}" >
 <listview
 android:id="@+id/lv_main"
 android:layout_width="match_parent"
 android:layout_height="match_parent" >
 </listview>
 <!-- com.atguigu.quickindex.quickindexview -->
 <com.atguigu.quickindex.quickindexview
 android:id="@+id/qiv_main"
 android:layout_width="40dp"
 android:layout_height="match_parent"
 android:layout_alignparentright="true"
 android:background="#ffffff" >
 </com.atguigu.quickindex.quickindexview>
 <textview
 android:id="@+id/tv_main_word"
 android:layout_width="100dp"
 android:layout_height="100dp"
 android:layout_centerhorizontal="true"
 android:layout_centervertical="true"
 android:background="#66666666"
 android:text="a"
 android:textsize="40sp"
 android:gravity="center"
 android:visibility="gone"/>
</relativelayout>

item:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?xml version="1.0" encoding="utf-8"?>
<linearlayout xmlns:android="http://schemas.android.com/apk/res/android"
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:orientation="vertical" >
 <textview
 android:id="@+id/tv_item_word"
 android:layout_width="fill_parent"
 android:layout_height="wrap_content"
 android:text="a"
 android:background="#66666666"
 android:textsize="18sp"
 android:padding="5dp"/>
 <textview
 android:id="@+id/tv_item_name"
 android:layout_width="fill_parent"
 android:layout_height="wrap_content"
 android:text="某人"
 android:textsize="18sp"
 android:padding="5dp"/>
</linearlayout>

自定义view:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
import android.content.context;
import android.graphics.canvas;
import android.graphics.color;
import android.graphics.paint;
import android.graphics.rect;
import android.util.attributeset;
import android.view.motionevent;
import android.view.view;
/**
 * 这里是自定义view
 * @author lxd
 *
 */
public class quickindexview extends view {
 private float itemwidth;
 private float itemheight;
 // private float wordwidth;
 // private float wordheight;
 private string[] indexarr = { "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 paint paint;
 public quickindexview(context context, attributeset attrs) {
 super(context, attrs);
 paint = new paint();
 paint.setcolor(color.white);
 paint.settextsize(16);
 paint.setantialias(true);
 }
 @override
 protected void onmeasure(int widthmeasurespec, int heightmeasurespec) {
 super.onmeasure(widthmeasurespec, heightmeasurespec);
 itemwidth = this.getmeasuredwidth();
 itemheight = this.getmeasuredheight() / 26f;
 }
 @override
 protected void ondraw(canvas canvas) {
 //当每次触发重绘的时候,就把26个字母循环一遍
 for (int i = 0; i < indexarr.length; i++) {
  string word = indexarr[i];
  // 设置文字的颜色
  if (i == touchindex) {
  //这里设置被点击的字母变化:颜色变灰色、字体变25sp
  paint.setcolor(color.gray);
  paint.settextsize(25);
  } else {
  //其他没被点击的字母,保持原有状态:设置颜色、字体大小为18sp
  paint.setcolor(color.black);
  paint.settextsize(18);
  }
  // 得到word的宽高
  rect bounds = new rect();
  paint.gettextbounds(word, 0, word.length(), bounds);
  //得到字体的宽
  int wordwidth = bounds.width();
  //得到字体的高
  int wordheight = bounds.height();
  // 计算word的左上角的坐标:字母所在的x坐标、y坐标
  float x = itemwidth / 2 - wordwidth / 2;
  float y = itemheight / 2 + wordheight / 2 + i * itemheight;
  // 绘制word
  canvas.drawtext(word, x, y, paint);
 }
 }
 // ///////////////////////////////////////////////////////////////////////
 private int touchindex = -1;// 触摸的字母的下标
 @override
 public boolean ontouchevent(motionevent event) {
 // 得到事件坐标
 float eventy = event.gety();
 switch (event.getaction()) {
 case motionevent.action_down:
 case motionevent.action_move:
  // 计算下标
  int index = (int) (eventy / itemheight);
  if (index > 25) {
  index = 25;
  }
  if (index < 0) {
  index = 0;
  }
  // 如果下标有改变, 强制重绘
  if (index != touchindex) {
  // 更新touchindex
  touchindex = index;
  // 强制重绘
  invalidate();
  // 通知activity更新textview
  if (onindexchangedlistener != null) {
   onindexchangedlistener.onindexchanged(indexarr[index]);
  }
  }
  break;
 case motionevent.action_up:
  touchindex = -1;
  // 强制重绘
  invalidate();
  // 通知activity更新textview
  if (onindexchangedlistener != null) {
  onindexchangedlistener.onup();
  }
  break;
 default:
  break;
 }
 return true;// 所有的事件都由当前视图消费
 }
 private onindexchangedlistener onindexchangedlistener;
 /*
 * 设置监听对象的方法 这个方法一般是activity调用
 */
 public void setonindexchangedlistener(
  onindexchangedlistener onindexchangedlistener) {
 this.onindexchangedlistener = onindexchangedlistener;
 }
 interface onindexchangedlistener {
 // 当操作的下标改变时自动调用
 public void onindexchanged(string word);
 // 当up时调用
 public void onup();
 }
}

联系人类:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
/**
 * 联系人类
 * @author lxd
 *
 */
public class friend implements comparable<friend> {
 private string name;
 private string pinyin;
 public friend(string name) {
 super();
 this.name = name;
 pinyin = pinyinutils.getpinyin(name);
 }
 public string getname() {
 return name;
 }
 public void setname(string name) {
 this.name = name;
 }
 public string getpinyin() {
 return pinyin;
 }
 public void setpinyin(string pinyin) {
 this.pinyin = pinyin;
 }
 @override
 public string tostring() {
 return "friend [name=" + name + ", pinyin=" + pinyin + "]";
 }
 @override
 public int compareto(friend another) {
 return this.pinyin.compareto(another.getpinyin());
 }
}

工具类:用于将汉字转换为拼音

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
/**
 * 将汉字转换为拼音
 * @author lxd
 *
 */
public class pinyinutils {
 /**
 * 得到指定汉字的拼音
 * 注意:不应该被频繁调用,它消耗一定内存
 * @param hanzi
 * @return
 */
 public static string getpinyin(string hanzi){
 string pinyin = "";
 hanyupinyinoutputformat format = new hanyupinyinoutputformat();//控制转换是否大小写,是否带音标
 format.setcasetype(hanyupinyincasetype.uppercase);//大写
 format.settonetype(hanyupinyintonetype.without_tone);
 //由于不能直接对多个汉字转换,只能对单个汉字转换
 char[] arr = hanzi.tochararray();
 for (int i = 0; i < arr.length; i++) {
  if(character.iswhitespace(arr[i]))continue;//如果是空格,则不处理,进行下次遍历
  //汉字是2个字节存储,肯定大于127,所以大于127就可以当为汉字转换
  if(arr[i]>127){
  try {
   //由于多音字的存在,单 dan shan
   string[] pinyinarr = pinyinhelper.tohanyupinyinstringarray(arr[i], format);
   if(pinyinarr!=null){
   pinyin += pinyinarr[0];
   }else {
   pinyin += arr[i];
   }
  } catch (badhanyupinyinoutputformatcombination e) {
   e.printstacktrace();
   //不是正确的汉字
   pinyin += arr[i];
  }
  }else {
  //不是汉字,
  pinyin += arr[i];
  }
 }
 return pinyin;
 }
}

以上代码是关于android手机联系人快速索引(手机通讯录)的全部叙述,希望大家喜欢。

原文链接:http://liuxudong1001.blog.51cto.com/10877072/1725990