
1.打开activity_main.xml
<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=".MainActivity" >
<ListView
android:id="@+id/lv"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
></ListView>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="18dp"
android:id="@+id/title_layout"
android:background="#303030"
android:orientation="vertical"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/title"
android:textColor="#ffffff"
/>
</LinearLayout>
</RelativeLayout>
布局文件很简单,一个用来展示联系人信息的ListView,还有一个LinearLayout,里面有一个TextView,它的作用是在头部始终显示一个当前分组.
2.新建item.xml布局,用于展示ListView的子项布局
<?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" >
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="18dp"
android:orientation="vertical"
android:background="#303030"
android:id="@+id/sort_key_layout"
>
<TextView
android:id="@+id/sort_key"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:textColor="#ffffff"
android:textSize="13sp"
/>
</LinearLayout>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="50dp"
android:orientation="horizontal"
android:id="@+id/name_layout"
>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:src="@drawable/icon"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/name"
/>
</LinearLayout>
</LinearLayout>
在这个布局文件中,首先是放入了一个和前面完成一样的分组布局,因为不仅界面头部需要展示分组,在每个分组内的第一个无素之前都需要展示分组布局。然后是加入一个简单的LinearLayout,里面包含了一个ImageView用于显示联系人头像,还包含一个TextView用于显示联系人姓名。
3.新建一个Contact.java,作为实体类
public class Contact {
private String name;//联系人姓名
private String SortKey; //排序字母
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSortKey() {
return SortKey;
}
public void setSortKey(String sortKey) {
SortKey = sortKey;
}
}
4.接下来就是联系人列表适配器
public class ContactAdapter extends ArrayAdapter<Contact> {
//需要渲染的Item布局
private int resource;
//字母表分组工具
private SectionIndexer mIndexer;
public ContactAdapter(Context context, int textViewResourceId, List<Contact> objects) {
super(context, textViewResourceId, objects);
resource = textViewResourceId;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
Contact contact=getItem(position);
LinearLayout layout=null;
if(convertView==null){
layout=(LinearLayout) LayoutInflater.from(getContext()).inflate(resource,null);
}
else{
layout=(LinearLayout) convertView;
}
TextView name=(TextView) layout.findViewById(R.id.name);
LinearLayout linearKeyLayout=(LinearLayout) layout.findViewById(R.id.sort_key_layout);
TextView sortKey=(TextView) layout.findViewById(R.id.sort_key);
name.setText(contact.getName());
int section=mIndexer.getSectionForPosition(position);
if(position==mIndexer.getPositionForSection(section)){
sortKey.setText(contact.getSortKey());
linearKeyLayout.setVisibility(View.VISIBLE);
}
else{
linearKeyLayout.setVisibility(View.GONE);
}
return layout;
}
public void setIndexer(SectionIndexer mIndexer){
this.mIndexer=mIndexer;
}
}
与往常不同的是,这个适配器不仅要排列联系人信息,还需要加上一个判断是否显示或隐藏当前分组信息.
5.打开MainActivity.java
public class MainActivity extends Activity {
//分组的布局
private LinearLayout titleLayout;
//分组上显示的字母
private TextView title;
//联系人ListView
private ListView contactListView;
//适配器
private ContactAdapter mAdapter;
//用于字母进行分组
private AlphabetIndexer indexer;
//存储卡中所有的联系人
private List<Contact> contactList=new ArrayList<Contact>();
//定义字母的排序规则
private String alphabet = "#ABCDEFGHIJKLMNOPQRSTUVWXYZ";
//上次第一个可见元素
private int lastFirstVisibleItem=-1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mAdapter=new ContactAdapter(this, R.layout.item, contactList);
titleLayout=(LinearLayout) findViewById(R.id.title_layout);
title=(TextView) findViewById(R.id.title);
contactListView=(ListView) findViewById(R.id.lv);
Uri uri=ContactsContract.CommonDataKinds.Phone.CONTENT_URI;
Cursor cursor = getContentResolver().query(uri,
new String[] { "display_name", "sort_key" }, null, null, "sort_key");
if(cursor.moveToFirst()){
do {
String name=cursor.getString(0);
String sort_name=getSortKey(cursor.getString(1));
Contact contact=new Contact();
contact.setName(name);
contact.setSortKey(sort_name);
contactList.add(contact);
} while (cursor.moveToNext());
}
startManagingCursor(cursor);
indexer=new AlphabetIndexer(cursor, 1, alphabet);
mAdapter.setIndexer(indexer);
if (contactList.size()>0) {
setupContactListView();
}
}
//为联系人ListView设置监听
private void setupContactListView(){
contactListView.setAdapter(mAdapter);
contactListView.setOnScrollListener(new OnScrollListener() {
@Override
public void onScrollStateChanged(AbsListView arg0, int arg1) {
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
int section =indexer.getSectionForPosition(firstVisibleItem);
int nextSectionPosition=indexer.getPositionForSection(section+1);
if(firstVisibleItem!=lastFirstVisibleItem){
MarginLayoutParams params=(MarginLayoutParams) titleLayout.getLayoutParams();
params.topMargin=0;
titleLayout.setLayoutParams(params);
title.setText(String.valueOf(alphabet.charAt(section)));
}
if(nextSectionPosition==firstVisibleItem+1){
View viewChild=view.getChildAt(0);
if(viewChild!=null){
int titleHeight=titleLayout.getHeight();
int bottom=viewChild.getBottom();
MarginLayoutParams params=(MarginLayoutParams) titleLayout.getLayoutParams();
if(bottom<titleHeight){
float pushedDistance=bottom-titleHeight;
params.topMargin=(int) pushedDistance;
titleLayout.setLayoutParams(params);
}
else{
if(params.topMargin!=0){
params.topMargin=0;
titleLayout.setLayoutParams(params);
}
}
}
}
lastFirstVisibleItem=firstVisibleItem;
}
});
}
/**
* 获取sort key的首个字符,如果是英文字母就直接返回,否则返回#。
*
* @param sortKeyString
* 数据库中读取出的sort key
* @return 英文字母或者#
*/
private String getSortKey(String sortKeyString) {
String key = sortKeyString.substring(0, 1).toUpperCase();
if (key.matches("[A-Z]")) {
return key;
}
return "#";
}
}
- Android系统联系人全特效实现(上),分组导航和挤压动画
记得在我刚接触Android的时候对系统联系人中的特效很感兴趣,它会根据手机中联系人姓氏的首字母进行分组,并在界面的最顶端始终显示一个当前的分组.如下图所示: 最让我感兴趣的是,当后一个分组和前一个分 ...
- Android系统联系人全特效实现(下),字母表快速滚动
在上一篇文章中,我和大家一起实现了类似于Android系统联系人的分组导航和挤压动画功能,不过既然文章名叫做<Android系统联系人全特效实现>,那么没有快速滚动功能显然是称不上&quo ...
- android系统联系人分组特效实现(2)---字母表快速滚动
要实现这种功能,只需要在 android系统联系人分组特效实现(1)---分组导航和挤压动画 的基础上再加上一个自定义控件即可完成. 1.新建项目,继续新建一个java类,BladeView,用 ...
- android 获取系统联系人 完全解析
一.代码 1.ContactsEngine.java import java.util.ArrayList; import java.util.HashMap; import java.util.Li ...
- android: 通过内容提供器读取系统联系人
读取系统联系人 由于我们之前一直使用的都是模拟器,电话簿里面并没有联系人存在,所以现在需要自 己手动添加几个,以便稍后进行读取.打开电话簿程序,界面如图 7.1 所示. 图 7.1 可以看到,目前 ...
- Android(java)学习笔记250:ContentProvider使用之获得系统联系人信息02(掌握)
1.重要: 系统删除一个联系人,默认情况下并不是把这个联系人直接删除掉了,只是做了一个标记,标记为被删除. 2.前面一讲说过了如何获取系统联系人信息(通过ContentProvider),获取联系人信 ...
- Android(java)学习笔记249:ContentProvider使用之获得系统联系人信息01
1.系统联系人的数据库(3张最重要的表) (1)raw_contacts 联系人表 保存联系人的id contact_id (2)data 数据表 保存联系人的数据 ( ...
- Android(java)学习笔记194:ContentProvider使用之获得系统联系人信息02(掌握)
1.重要: 系统删除一个联系人,默认情况下并不是把这个联系人直接删除掉了,只是做了一个标记,标记为被删除. 2.前面一讲说过了如何获取系统联系人信息(通过ContentProvider),获取联系人信 ...
- Android(java)学习笔记193:ContentProvider使用之获得系统联系人信息01
1.系统联系人的数据库(3张最重要的表) (1)raw_contacts 联系人表 保存联系人的id contact_id (2)data 数据表 保存联系人的数据 ( ...
随机推荐
- 用蒙特卡洛方法计算派-python和R语言
用蒙特卡洛方法算pi-基于python和R语言 最近follow了MOOC上一门python课,开始学Python.同时,买来了概率论与数理统计,准备自学一下统计.(因为被鄙视过不是统计专业却想搞数据 ...
- Java面试不得不知的问题(一)
程序员面试 1. 面向对象的特征有哪些方面 · 抽象:抽象就是忽略一个主题中与当前目标无关的那些方面,以便更充分地注意与当前目标有关的方面.抽象并不打算了解全部问题,而只是选择其中的一部分, ...
- 爬虫学习(十一)——bs4基础学习
ba4的介绍: bs4是第三方提供的库,可以将网页生成一个对象,这个网页对象有一些函数和属性,可以快捷的获取网页中的内容和标签 lxml的介绍 lxml是一个文件的解释器,python自带的解释器是: ...
- ssm整合-图片上传功能(转)
本文介绍 ssm (Spring+SpringMVC+Mybatis)实现上传功能. 以一个添加用户的案例介绍(主要是将上传文件). 一.需求介绍 我们要实现添加用户的时候上传图片(其实任何文件都可以 ...
- Mybatis-传参
单参数传递 在mapper文件使用动态SQL时,传入参数的名称任意.不影响参数传入的结果 多参数传递 默认传递方式 自动将传入的参数进行排序,并用arg1…argeN或者param1…paramN赋值 ...
- ubuntu16 升级pip3后报错File "/usr/bin/pip3", line 9, in <module> from pip import main ImportError: cannot import name 'main'
问题:ubuntu16 执行pip3 install --upgrade pip之后,pip3执行出错. Traceback (most recent call last): File "/ ...
- Python--基础2
class Ball: #def setname(self,name): def __init__(self,name): self.name = name def __kick(self): #__ ...
- 【转载】C#批量插入数据到Sqlserver中的三种方式
引用:https://m.jb51.net/show/99543 这篇文章主要为大家详细介绍了C#批量插入数据到Sqlserver中的三种方式,具有一定的参考价值,感兴趣的小伙伴们可以参考一下 本篇, ...
- ASPX页面请求响应过程
- 《算法》第四版 IDEA 运行环境的搭建
<算法>第四版 IDEA 运行环境的搭建 新建 模板 小书匠 在搭建之初,我是想不到会出现如此之多的问题.我看了网上的大部分教程,都是基于Eclipse搭建的,还没有使用IDEA搭建的教程 ...