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系统联系人分组特效实现(1)---分组导航和挤压动画的更多相关文章

  1. Android系统联系人全特效实现(上),分组导航和挤压动画

    记得在我刚接触Android的时候对系统联系人中的特效很感兴趣,它会根据手机中联系人姓氏的首字母进行分组,并在界面的最顶端始终显示一个当前的分组.如下图所示: 最让我感兴趣的是,当后一个分组和前一个分 ...

  2. Android系统联系人全特效实现(下),字母表快速滚动

    在上一篇文章中,我和大家一起实现了类似于Android系统联系人的分组导航和挤压动画功能,不过既然文章名叫做<Android系统联系人全特效实现>,那么没有快速滚动功能显然是称不上&quo ...

  3. android系统联系人分组特效实现(2)---字母表快速滚动

    要实现这种功能,只需要在   android系统联系人分组特效实现(1)---分组导航和挤压动画  的基础上再加上一个自定义控件即可完成. 1.新建项目,继续新建一个java类,BladeView,用 ...

  4. android 获取系统联系人 完全解析

    一.代码 1.ContactsEngine.java import java.util.ArrayList; import java.util.HashMap; import java.util.Li ...

  5. android: 通过内容提供器读取系统联系人

    读取系统联系人 由于我们之前一直使用的都是模拟器,电话簿里面并没有联系人存在,所以现在需要自 己手动添加几个,以便稍后进行读取.打开电话簿程序,界面如图 7.1 所示. 图   7.1 可以看到,目前 ...

  6. Android(java)学习笔记250:ContentProvider使用之获得系统联系人信息02(掌握)

    1.重要: 系统删除一个联系人,默认情况下并不是把这个联系人直接删除掉了,只是做了一个标记,标记为被删除. 2.前面一讲说过了如何获取系统联系人信息(通过ContentProvider),获取联系人信 ...

  7. Android(java)学习笔记249:ContentProvider使用之获得系统联系人信息01

    1.系统联系人的数据库(3张最重要的表) (1)raw_contacts  联系人表        保存联系人的id   contact_id (2)data 数据表       保存联系人的数据 ( ...

  8. Android(java)学习笔记194:ContentProvider使用之获得系统联系人信息02(掌握)

    1.重要: 系统删除一个联系人,默认情况下并不是把这个联系人直接删除掉了,只是做了一个标记,标记为被删除. 2.前面一讲说过了如何获取系统联系人信息(通过ContentProvider),获取联系人信 ...

  9. Android(java)学习笔记193:ContentProvider使用之获得系统联系人信息01

    1.系统联系人的数据库(3张最重要的表) (1)raw_contacts  联系人表        保存联系人的id   contact_id (2)data 数据表       保存联系人的数据 ( ...

随机推荐

  1. linux flushing file system caches

    We may drop the file system caches on Linux to free up memory for applications. Kernels 2.6.16 and n ...

  2. 第49章 在SRAM中调试代码—零死角玩转STM32-F429系列

    第49章     在SRAM中调试代码 全套200集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn 野火视频教程优酷观看网址:http://i.youku.com/fir ...

  3. js 图片库 改进版

    平稳退化 js与html标记分离? 如果有两个函数:firstFunction和secondFunction,如果想让它们俩都在页面加载时得到执行,可以调用函数addLoadEvent,只有一个参数, ...

  4. 【MySQL】使用SQL语句操作MySQL

    前言: MySQL在工作中是最常用的数据库,但在使用Django和Flask的时候,都是使用ORM进行操作,除了select语句外,其他的SQL语句操作MySQL的能力没有啥提高,为了解决这个问题, ...

  5. zabbix服务端安装配置

    1.安装好httpd,mysql,php yum install httpd php mysql mysql-devel php-xmlwriter php-gd php-mbstring php-b ...

  6. js | javascript实现浏览器窗口大小被改变时触发事件的方法

    转载 当浏览器的窗口大小被改变时触发的事件window.onresize 为事件指定代码: 代码如下: window.onresize = function(){ } 例如: 浏览器可见区域信息: 代 ...

  7. Python 遗传算法实现字符串

    Python 遗传算法实现字符串 流程 1. 初始化 2. 适应度函数 3. 选择 4. 交叉 5. 变异 适应度函数计算方法 计算个体间的差:分别计算每个元素与目标元素的差取平方和 种群:计算总体均 ...

  8. 【Python 2 到 3 系列】 此整型非彼整型

    v2.2 (2.x)以后,python支持不会溢出的 long 型. v3.0后,确切的讲, int 型(依赖运行环境C编译器中long型的精度)消失了,long型替代 int 型,成为新的.不依赖运 ...

  9. python__系统 : 进程

    在类unix操作系统下,可以用 os.fork() 创建一个新的进程,windows系统不可以: import os ret = os.fork() print('ret=%d' % ret) : p ...

  10. QWidget 自带的最大化,最小化,关闭按键的设置

    使用函数 setWindowFlags 参数: CustomizeWindowHint 去掉窗口所有自带按钮 Qt::CustomizeWindowHint | Qt::WindowCloseButt ...