- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章Android仿微信联系人按字母排序由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
app只要涉及到联系人的界面,几乎都是按照字母排序以及导航栏的方式。既然这个需求这么火,于是开始学习相关内容,此篇文章是我通过参考网上资料独立编写和总结的,希望多多少少对大家有所帮助,写的不好,还请各位朋友指教.
效果图如下:
实现这个效果,需要三个知识点 : 1:将字符串 进行拼音分类 2:expandablelistview 二级扩展列表 3:右边字母分类view 。
我们先一个一个来了解解决方案,再上代码.
实现字母分类:
字母分类又分为三个小要点:一个是将中文转化为拼音,一个是实现按照字母的顺序排序,另一个是字母只显示在具有相同首字母中文的第一个前面.
1、将中文转化为拼音,这里使用了一个工具包,即pinyin4j-2.5.0.jar。官网地址:http://pinyin4j.sourceforge.net/ 点击下载,导入项目即可。(至于教程,网上很多) 。
在这里我们只需要使用将中文转换成拼音的代码即可.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
pinyinutils.java
public
static
string getpingyin(string inputstring) {
hanyupinyinoutputformat format =
new
hanyupinyinoutputformat();
format.setcasetype(hanyupinyincasetype.lowercase);
format.settonetype(hanyupinyintonetype.without_tone);
format.setvchartype(hanyupinyinvchartype.with_v);
char
[] input = inputstring.trim().tochararray();
string output =
""
;
try
{
for
(
char
curchar : input) {
if
(java.lang.character.tostring(curchar).matches(
"[\\u4e00-\\u9fa5]+"
)) {
string[] temp = pinyinhelper.tohanyupinyinstringarray(curchar, format);
output += temp[
0
];
}
else
output += java.lang.character.tostring(curchar);
}
}
catch
(badhanyupinyinoutputformatcombination e) {
e.printstacktrace();
}
return
output;
}
|
2、实现按照字母的顺序排序,使用的是java自带的comparator接口,利用之前获取到的中文拼音,得到首字母并根据ascii值来实现排序.
1
2
3
4
5
6
7
8
9
10
11
12
|
private
int
sort(personbean lhs, personbean rhs) {
// 获取ascii值
int
lhs_ascii = lhs.getfirstpinyin().touppercase().charat(
0
);
int
rhs_ascii = rhs.getfirstpinyin().touppercase().charat(
0
);
// 判断若不是字母,则排在字母之后
if
(lhs_ascii <
65
|| lhs_ascii >
90
)
return
1
;
else
if
(rhs_ascii <
65
|| rhs_ascii >
90
)
return
-
1
;
else
return
lhs.getpinyin().compareto(rhs.getpinyin());
}
|
3、字母只显示在具有相同首字母中文的第一个前面。这里算是一个小技巧,这里字母显示的布局与中文名字的布局都是存放在listview的item的布局中的.
item的布局如下:
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
|
<?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=
"match_parent"
android:orientation=
"vertical"
>
<!-- 这个textview就是显示字母的 -->
<textview
android:id=
"@+id/tv_lv_item_tag"
android:layout_width=
"match_parent"
android:layout_height=
"20dp"
android:background=
"#e6e6e6"
android:gravity=
"center_vertical"
android:paddingleft=
"10dip"
android:text=
"z"
android:visibility=
"visible"
/>
<relativelayout
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
>
<view
android:id=
"@+id/view_lv_item_line"
android:layout_width=
"match_parent"
android:layout_height=
"0.5dip"
android:background=
"#174465"
android:layout_marginleft=
"10dip"
android:layout_marginright=
"20dip"
/>
<imageview
android:id=
"@+id/iv_lv_item_head"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:src=
"@drawable/ic_launcher"
android:layout_below=
"@id/view_lv_item_line"
android:layout_marginleft=
"5dp"
/>
<textview
android:id=
"@+id/tv_lv_item_name"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:layout_centervertical=
"true"
android:layout_torightof=
"@id/iv_lv_item_head"
android:layout_marginleft=
"5dip"
android:text=
"周华健"
/>
</relativelayout>
</linearlayout>
|
而判断是否需要显示字母,是通过判断当前item的position是否等于第一个出现item对应的中文首字母的索引.
如果相等,则说明是第一次出现,便需要显示字母,否则不显示字母。而这样的判断,有一个前提,那就是中文拼音的排序必须是按照字母顺序排序的,这就是我们在上一步排序的必要。 实现右侧的字母导航: 右侧的字母导航,其本质就是一个自定义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
|
package
com.suse.contact;
import
android.content.context;
import
android.graphics.canvas;
import
android.graphics.color;
import
android.graphics.paint;
import
android.graphics.typeface;
import
android.graphics.drawable.colordrawable;
import
android.util.attributeset;
import
android.view.motionevent;
import
android.view.view;
import
android.widget.textview;
public
class
sidebar
extends
view {
// 触摸事件
private
ontouchingletterchangedlistener ontouchingletterchangedlistener;
// 26个字母
public
static
string[] a_z = {
"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;
/**
* 为sidebar设置显示字母的textview
* @param 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 / a_z.length-
2
;
// 获取每一个字母的高度 (这里-2仅仅是为了好看而已)
for
(
int
i =
0
; i < a_z.length; i++) {
paint.setcolor(color.rgb(
33
,
65
,
98
));
//设置字体颜色
paint.settypeface(typeface.default_bold);
//设置字体
paint.setantialias(
true
);
//设置抗锯齿
paint.settextsize(
30
);
//设置字母字体大小
// 选中的状态
if
(i == choose) {
paint.setcolor(color.parsecolor(
"#3399ff"
));
//选中的字母改变颜色
paint.setfakeboldtext(
true
);
//设置字体为粗体
}
// x坐标等于中间-字符串宽度的一半.
float
xpos = width /
2
- paint.measuretext(a_z[i]) /
2
;
float
ypos = singleheight * i + singleheight;
canvas.drawtext(a_z[i], xpos, ypos, paint);
//绘制所有的字母
paint.reset();
// 重置画笔
}
}
@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() * a_z.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
:
setbackgroundresource(r.drawable.sidebar_background);
if
(oldchoose != c) {
//判断选中字母是否发生改变
if
(c >=
0
&& c < a_z.length) {
if
(listener !=
null
) {
listener.ontouchingletterchanged(a_z[c]);
}
if
(mtextdialog !=
null
) {
mtextdialog.settext(a_z[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);
}
}
|
接下来就是mainactivity和sortadapter的代码了.
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
|
mainactivity.java:
package
com.suse.contact;
import
java.util.arraylist;
import
java.util.collections;
import
java.util.list;
import
android.app.activity;
import
android.os.bundle;
import
android.widget.listview;
import
android.widget.textview;
import
com.suse.contact.sidebar.ontouchingletterchangedlistener;
/**
*
* @classname: mainactivity
* @description: todo(这里用一句话描述这个类的作用)
* @author 银色的流星 欢迎批评、指导、交流 qq:962455668
*/
public
class
mainactivity
extends
activity {
private
listview listview;
private
sortadapter sortadapter;
private
list<personbean> data;
private
sidebar sidebar;
private
textview dialog;
@override
protected
void
oncreate(bundle savedinstancestate) {
super
.oncreate(savedinstancestate);
setcontentview(r.layout.activity_main);
init();
}
private
list<personbean> getdata(string[] data) {
list<personbean> listarray =
new
arraylist<personbean>();
for
(
int
i =
0
; i < data.length; i++) {
string pinyin = pinyinutils.getpingyin(data[i]);
string fpinyin = pinyin.substring(
0
,
1
).touppercase();
personbean person =
new
personbean();
person.setname(data[i]);
person.setpinyin(pinyin);
// 正则表达式,判断首字母是否是英文字母
if
(fpinyin.matches(
"[a-z]"
)) {
person.setfirstpinyin(fpinyin);
}
else
{
person.setfirstpinyin(
"#"
);
}
listarray.add(person);
}
return
listarray;
}
private
void
init() {
// todo auto-generated method stub
sidebar = (sidebar) findviewbyid(r.id.sidebar);
listview = (listview) findviewbyid(r.id.listview);
dialog = (textview) findviewbyid(r.id.dialog);
sidebar.settextview(dialog);
// 设置字母导航触摸监听
sidebar.setontouchingletterchangedlistener(
new
ontouchingletterchangedlistener() {
@override
public
void
ontouchingletterchanged(string s) {
// todo auto-generated method stub
// 该字母首次出现的位置
int
position = sortadapter.getpositionforselection(s.charat(
0
));
if
(position != -
1
) {
listview.setselection(position);
}
}
});
data = getdata(getresources().getstringarray(r.array.listpersons));
// 数据在放在adapter之前需要排序
collections.sort(data,
new
pinyincomparator());
sortadapter =
new
sortadapter(
this
, data);
listview.setadapter(sortadapter);
}
}
|
sortadapter.java
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
|
package
com.suse.contact;
import
java.util.list;
import
android.content.context;
import
android.view.layoutinflater;
import
android.view.view;
import
android.view.viewgroup;
import
android.widget.baseadapter;
import
android.widget.textview;
public
class
sortadapter
extends
baseadapter {
private
context context;
private
list<personbean> persons;
private
layoutinflater inflater;
public
sortadapter(context context, list<personbean> persons) {
this
.context = context;
this
.persons = persons;
this
.inflater = layoutinflater.from(context);
}
@override
public
int
getcount() {
// todo auto-generated method stub
return
persons.size();
}
@override
public
object getitem(
int
position) {
// todo auto-generated method stub
return
persons.get(position);
}
@override
public
long
getitemid(
int
position) {
// todo auto-generated method stub
return
position;
}
@override
public
view getview(
int
position, view convertview, viewgroup parent) {
viewholder viewholder =
null
;
personbean person = persons.get(position);
if
(convertview ==
null
) {
viewholder =
new
viewholder();
convertview = inflater.inflate(r.layout.list_item,
null
);
viewholder.tv_tag = (textview) convertview
.findviewbyid(r.id.tv_lv_item_tag);
viewholder.tv_name = (textview) convertview
.findviewbyid(r.id.tv_lv_item_name);
convertview.settag(viewholder);
}
else
{
viewholder = (viewholder) convertview.gettag();
}
// 获取首字母的assii值
int
selection = person.getfirstpinyin().charat(
0
);
// 通过首字母的assii值来判断是否显示字母
int
positionforselection = getpositionforselection(selection);
if
(position == positionforselection) {
// 相等说明需要显示字母
viewholder.tv_tag.setvisibility(view.visible);
viewholder.tv_tag.settext(person.getfirstpinyin());
}
else
{
viewholder.tv_tag.setvisibility(view.gone);
}
viewholder.tv_name.settext(person.getname());
return
convertview;
}
public
int
getpositionforselection(
int
selection) {
for
(
int
i =
0
; i < persons.size(); i++) {
string fpinyin = persons.get(i).getfirstpinyin();
char
first = fpinyin.touppercase().charat(
0
);
if
(first == selection) {
return
i;
}
}
return
-
1
;
}
class
viewholder {
textview tv_tag;
textview tv_name;
}
}
|
虽然不全,但比较重要的代码都已经贴上去了,希望对大家有所帮助 。
最后此篇关于Android仿微信联系人按字母排序的文章就讲到这里了,如果你想了解更多关于Android仿微信联系人按字母排序的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我最近在/ drawable中添加了一些.gifs,以便可以将它们与按钮一起使用。这个工作正常(没有错误)。现在,当我重建/运行我的应用程序时,出现以下错误: Error: Gradle: Execu
Android 中有返回内部存储数据路径的方法吗? 我有 2 部 Android 智能手机(Samsung s2 和 s7 edge),我在其中安装了一个应用程序。我想使用位于这条路径中的 sqlit
这个问题在这里已经有了答案: What's the difference between "?android:" and "@android:" in an android layout xml f
我只想知道 android 开发手机、android 普通手机和 android root 手机之间的实际区别。 我们不能从实体店或除 android marketplace 以外的其他地方购买开发手
自Gradle更新以来,我正在努力使这个项目达到标准。这是一个团队项目,它使用的是android-apt插件。我已经进行了必要的语法更改(编译->实现和apt->注释处理器),但是编译器仍在告诉我存在
我是android和kotlin的新手,所以请原谅要解决的一个非常简单的问题! 我已经使用导航体系结构组件创建了一个基本应用程序,使用了底部的导航栏和三个导航选项。每个导航选项都指向一个专用片段,该片
我目前正在使用 Facebook official SDK for Android . 我现在正在使用高级示例应用程序,但我不知道如何让它获取应用程序墙/流/状态而不是登录的用户。 这可能吗?在那种情
我在下载文件时遇到问题, 我可以在模拟器中下载文件,但无法在手机上使用。我已经定义了上网和写入 SD 卡的权限。 我在服务器上有一个 doc 文件,如果用户单击下载。它下载文件。这在模拟器中工作正常但
这个问题在这里已经有了答案: What is the difference between gravity and layout_gravity in Android? (22 个答案) 关闭 9
任何人都可以告诉我什么是 android 缓存和应用程序缓存,因为当我们谈论缓存清理应用程序时,它的作用是,缓存清理概念是清理应用程序缓存还是像内存管理一样主存储、RAM、缓存是不同的并且据我所知,缓
假设应用程序 Foo 和 Eggs 在同一台 Android 设备上。任一应用程序都可以获取设备上所有应用程序的列表。一个应用程序是否有可能知道另一个应用程序是否已经运行以及运行了多长时间? 最佳答案
我有点困惑,我只看到了从 android 到 pc 或者从 android 到 pc 的例子。我需要制作一个从两部手机 (android) 连接的 android 应用程序进行视频聊天。我在想,我知道
用于使用 Android 以编程方式锁定屏幕。我从 Stackoverflow 之前关于此的问题中得到了一些好主意,并且我做得很好,但是当我运行该代码时,没有异常和错误。而且,屏幕没有锁定。请在这段代
文档说: android:layout_alignParentStart If true, makes the start edge of this view match the start edge
我不知道这两个属性和高度之间的区别。 以一个TextView为例,如果我将它的layout_width设置为wrap_content,并将它的width设置为50 dip,会发生什么情况? 最佳答案
这两个属性有什么关系?如果我有 android:noHistory="true",那么有 android:finishOnTaskLaunch="true" 有什么意义吗? 最佳答案 假设您的应用中有
我是新手,正在尝试理解以下 XML 代码: 查看 developer.android.com 上的文档,它说“starStyle”是 R.attr 中的常量, public static final
在下面的代码中,为什么当我设置时单选按钮的外观会发生变化 android:layout_width="fill_parent" 和 android:width="fill_parent" 我说的是
很难说出这里要问什么。这个问题模棱两可、含糊不清、不完整、过于宽泛或夸夸其谈,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开,visit the help center . 关闭 9
假设我有一个函数 fun myFunction(name:String, email:String){},当我调用这个函数时 myFunction('Ali', 'ali@test.com ') 如何
我是一名优秀的程序员,十分优秀!