联系人列表字母排序索引(三)

也是忙忙碌碌好几天,今天又有时间了,继续这个文章的编写。今天是这篇文章的最后一部分。主要内容包括以下几点:

1.将中文名字转化成拼音,并提取首字母,进行排序。

2.实现分组列表Adapter模板。

3.将列表与索引结合在一起。

pinyin4j是一个将中文转化成拼音的高效工具,我的源码中带了这个依赖包。通过这个工具,可以先获取一个中文的拼音。

    public static String getLetter(String name) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < name.length(); i++) {
            char c = name.charAt(i);
            String[] str = PinyinHelper.toHanyuPinyinStringArray(c);
            if (str != null && str.length >= 1) {
                sb.append(str[0].charAt(0));
            } else {
                sb.append(c);
            }

        }
        return sb.toString();
    }

PinyinHelper.tohanyuPinyinStringArray(),将每个char转化成拼音,我这里只提取每个汉字的第一个拼音字母,最后返回的结果是字符串的拼音简写。比如:张三丰---zsf

上面的步骤,已经可以将中文转化成拼音简写了,下面,要做的是什么呢?

下面的思路是这样的:

1.先对列表数据按字母顺序排序。

2.adapter的每一个itemView都是带字母分组头和内容的。只是,只有在一组中文开头的首个位置才显示。也就是说,张三丰,张君宝等,排在第一个的显示头部,也就是z,其他的隐藏头部。所以这个位置要计算出来。

3.因为每一个item包含了头部,所以,点击事件需要在真实内容区域,不在头部。因此,ListView的点击事件需要禁用,把事件写在adapter的内容控件上。

1.1.先对字母排序,排序需要知道排序的内容,先定义一个接口:

package com.mjc.contactlistdemo.sort_by_letter;

/**
 * Created by mjc on 2016/5/24.
 */
public interface ISort {
    String getSortName();
}

之后,我们需要使用的数据,只要继承他,就可以使用我的带字母索引列表。

1.2.自定义排序方法:

排序的方法,需要我们借助Collections的sorts方法来排序:

/**
     * 按照字母排序
     *
     * @param list
     * @return
     */
    public static <T extends ISort> void sortByLetter(ArrayList<T> list) {
        Collections.sort(list, new Comparator<T>() {
            @Override
            public int compare(T lhs, T rhs) {
                String l = getLetter(lhs.getSortName());
                String r = getLetter(rhs.getSortName());
                int minLength = Math.min(l.length(), r.length());
                int result = 0;
                for (int i = 0; i < minLength; i++) {
                    if (l.charAt(i) < r.charAt(i)) {
                        result = -1;
                        break;
                    } else if (l.charAt(i) > r.charAt(i)) {
                        result = 1;
                        break;
                    } else {
                        result = 0;
                        continue;
                    }

                }

                if (result == 0) {
                    return l.length() > r.length() ? 1 : -1;
                }
                return result;
            }
        });
    }

用的是泛型,只要实现了Isort的实体类,都可以用它来排序。排序的过程,主要是compare方法,这个方法的返回值,决定了你的排序。每次比较两个数值,结果由返回值决定。具体的说,就是lhs要排在rhs左边,返回值就要小于0,;反之,一样。

2.1.Adapter的实现。

我将计算都提取到了一个BaseSortByLetterAdapter里面,但是在子Adapter里面,需要调用BaseSortByLetterAdapter的方法,得到第一个分组的位置。

package com.mjc.contactlistdemo.sort_by_letter;

import android.widget.BaseAdapter;
import android.widget.SectionIndexer;

import java.util.ArrayList;

/**
 * Created by mjc on 2016/5/24.
 */
public abstract class BaseSortByLetterAdapter<T> extends BaseAdapter implements SectionIndexer {
    protected String[] sections;
    protected ArrayList<T> datas;

    public BaseSortByLetterAdapter(ArrayList<T> datas) {
        sections = new String[]{ "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","#"};
        this.datas = datas;
    }

    @Override
    public String[] getSections() {

        return sections;
    }

    //需要进行排序的字符串
    protected abstract String getSortString(T bean);

    //通过section位置,获取首个position位置
    @Override
    public int getPositionForSection(int sectionIndex) {
        String section = sections[sectionIndex];
        //todo ListView的数据要按照字母顺序排列
        for (int i = 0; i < getCount(); i++) {
            T bean = datas.get(i);
            String headerLetter = SortUtil.getLetter(getSortString(bean));

            if (String.valueOf(headerLetter.charAt(0)).equalsIgnoreCase(section)) {
                return i;
            } else if (sectionIndex == 0) {
                return 0;
            }
        }
        return -1;
    }

    //通过位置获取sectionIndex位置
    @Override
    public int getSectionForPosition(int position) {
        T bean = datas.get(position);
        String name = getSortString(bean);
        String letter = SortUtil.getLetter(name);
        String header = String.valueOf(letter.charAt(0));
        for (int i = 0; i < sections.length; i++) {
            if (sections[i].equalsIgnoreCase(header)) {
                return i;
            }
        }
        return 0;
    }

    public int getSectionIndex(String section) {
        for (int i = 0; i < sections.length; i++) {
            if (section.equalsIgnoreCase(sections[i])) {
                return i;
            }
        }
        return 0;
    }

}

implements SectionIndexer,这个东西不是重点,他的作用是,当你开启ListView的快速滑动后,拖动滑动条是可以显示当前所处的数据的字母。只不过我这里实现方式,和系统的原理差不多,因此也是实现了这个接口,之后用到我们的IndexView上就好。

这里面重要的一点是:我们需要知道第一个字母出现的位置,以便于我们现实这个位置的title字母,其他位置隐藏。这样我们的分组效果就能实现了。   为了获取这个位置,我们的逻辑是这样的:通过位置获取当前位置的字母,再通过这个字母获取这个字母在列表中的第一个位置,如果第一个位置和当前位置相同则表示是第一个位置。上面的主要两个方法就是为这个服务的。

通过位置获取对应的字母字母的位置,原理很简单,先获取当前数据的排序字母,然后和字母列表比较,得到字母的位置。

  @Override
    public int getSectionForPosition(int position) {
        T bean = datas.get(position);
        String name = getSortString(bean);
        String letter = SortUtil.getLetter(name);
        String header = String.valueOf(letter.charAt(0));
        for (int i = 0; i < sections.length; i++) {
            if (sections[i].equalsIgnoreCase(header)) {
                return i;
            }
        }
        return 0;
    }

再通过字母的位置,获取列表中第一个数据的位置,之后在getView中将这个位置和当前位置做比较,如果相等,就显示title,不相等就隐藏。

 //通过section位置,获取首个position位置
    @Override
    public int getPositionForSection(int sectionIndex) {
        String section = sections[sectionIndex];
        //todo ListView的数据要按照字母顺序排列
        for (int i = 0; i < getCount(); i++) {
            T bean = datas.get(i);
            String headerLetter = SortUtil.getLetter(getSortString(bean));

            if (String.valueOf(headerLetter.charAt(0)).equalsIgnoreCase(section)) {
                return i;
            } else if (sectionIndex == 0) {
                return 0;
            }
        }
        return -1;
    }

到这里,基本是结束了,接下来是使用方法:

1.定义一个实体类,实现Isort接口。

2.定义一个Adpater,继承BaseSortByLetterAdapter

3.Activity中,setAdapter之前,先使用SortUtil对数据进行排序。

ContactEntity.class

package com.mjc.contactlistdemo.core.contact.entity;

import com.mjc.contactlistdemo.sort_by_letter.ISort;

/**
 * Created by mjc on 2016/5/12.
 */
public class ContactEntity implements ISort {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String getSortName() {
        return name;
    }
}

ContactAdapter.class

package com.mjc.contactlistdemo.core.contact;

import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import com.mjc.contactlistdemo.R;
import com.mjc.contactlistdemo.core.contact.entity.ContactEntity;
import com.mjc.contactlistdemo.sort_by_letter.BaseSortByLetterAdapter;

import java.util.ArrayList;

/**
 * Created by mjc on 2016/5/24.
 */
public class ContactAdapter extends BaseSortByLetterAdapter<ContactEntity> {

    public ContactAdapter(ArrayList<ContactEntity> datas) {
        super(datas);
    }

    @Override
    protected String getSortString(ContactEntity bean) {
        return bean.getSortName();
    }

    @Override
    public int getCount() {
        return datas.size();
    }

    @Override
    public Object getItem(int position) {
        return null;
    }

    @Override
    public long getItemId(int position) {
        return 0;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        Holder mHolder;
        if (convertView == null) {
            mHolder = new Holder();
            convertView = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_contact, null);
            mHolder.mNameTv = (TextView) convertView.findViewById(R.id.tv_name);
            mHolder.mIndexTv = (TextView) convertView.findViewById(R.id.tv_index);
            convertView.setTag(mHolder);
        } else {
            mHolder = (Holder) convertView.getTag();
        }
        //强转需要注意原来的类型
        ContactEntity bean =  datas.get(position);
        //获取对应字母的位置
        int index = getSectionForPosition(position);
        //比较列表中第一个字母的位置和这个位置是否相等
        if (getPositionForSection(index) == position) {
            mHolder.mIndexTv.setVisibility(View.VISIBLE);
            mHolder.mIndexTv.setText(sections[index]);
        } else {
            mHolder.mIndexTv.setVisibility(View.GONE);
        }
        mHolder.mNameTv.setText(bean.getName());
        return convertView;
    }

    class Holder {
        public TextView mNameTv;
        public TextView mIndexTv;
    }
}

item_contact.xml

<?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
        android:id="@+id/tv_index"
        style="@style/KeyStyle"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#f4f6f3"
        android:paddingTop="12dp"
        android:paddingBottom="4dp"
        android:textSize="14sp" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#fdfdfd"
        android:gravity="center_vertical"
        android:orientation="horizontal">

        <ImageView
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:paddingBottom="5dp"
            android:paddingLeft="10dp"
            android:paddingTop="5dp"
            android:src="@mipmap/ic_launcher"
            android:visibility="gone" />

        <TextView
            android:id="@+id/tv_name"
            style="@style/InputStyle"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:padding="10dp"
            android:textSize="16sp" />
    </LinearLayout>
</LinearLayout>

MainActivity.class

package com.mjc.contactlistdemo.core.contact;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.ListView;

import com.mjc.contactlistdemo.R;
import com.mjc.contactlistdemo.core.contact.entity.ContactEntity;
import com.mjc.contactlistdemo.sort_by_letter.IndexView;
import com.mjc.contactlistdemo.sort_by_letter.LetterWindow;
import com.mjc.contactlistdemo.sort_by_letter.SortUtil;

import java.util.ArrayList;

public class MainActivity extends AppCompatActivity implements IndexView.OnCharTouchEvent {

    private LetterWindow mLetterWindow;
    private ContactAdapter mContactAdapter;
    private IndexView mIndexView;
    private ListView mList;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mList = (ListView) findViewById(R.id.list);
        mIndexView = (IndexView) findViewById(R.id.civ);
        mIndexView.setOnLetterTouchedListener(this);
        mLetterWindow = new LetterWindow(this);
        ArrayList<ContactEntity> list = new ArrayList<>();
        ContactEntity bean1 = new ContactEntity();
        bean1.setName("单熊信");

        ContactEntity bean2 = new ContactEntity();
        bean2.setName("谢天华");

        ContactEntity bean3 = new ContactEntity();
        bean3.setName("李自成");

        ContactEntity bean4 = new ContactEntity();
        bean4.setName("段天涯");

        ContactEntity bean5 = new ContactEntity();
        bean5.setName("张无忌");

        ContactEntity bean6 = new ContactEntity();
        bean6.setName("小红");

        ContactEntity bean7 = new ContactEntity();
        bean7.setName("李寻欢");

        ContactEntity bean8 = new ContactEntity();
        bean8.setName("王小亚");

        ContactEntity bean9 = new ContactEntity();
        bean9.setName("夏冬青");

        ContactEntity bean10 = new ContactEntity();
        bean10.setName("上官锦");

        ContactEntity bean11 = new ContactEntity();
        bean11.setName("炎亚纶");

        ContactEntity bean12 = new ContactEntity();
        bean12.setName("刘德华");

        ContactEntity bean13 = new ContactEntity();
        bean13.setName("陈浩民");

        ContactEntity bean14 = new ContactEntity();
        bean14.setName("马云");

        ContactEntity bean15 = new ContactEntity();
        bean15.setName("雷军");

        ContactEntity bean16 = new ContactEntity();
        bean16.setName("周宏伟");

        ContactEntity bean17 = new ContactEntity();
        bean17.setName("李易峰");

        ContactEntity bean18 = new ContactEntity();
        bean18.setName("鹿晗");

        ContactEntity bean19 = new ContactEntity();
        bean19.setName("邓超");

        ContactEntity bean20 = new ContactEntity();
        bean20.setName("李晨");

        ContactEntity bean21 = new ContactEntity();
        bean21.setName("张翰");

        ContactEntity bean22 = new ContactEntity();
        bean22.setName("邓丽君");

        ContactEntity bean23 = new ContactEntity();
        bean23.setName("曾志伟");

        ContactEntity bean24 = new ContactEntity();
        bean24.setName("阿甘");

        ContactEntity bean25 = new ContactEntity();
        bean25.setName("爸比");

        ContactEntity bean26 = new ContactEntity();
        bean26.setName("东方彧卿");

        ContactEntity bean27 = new ContactEntity();
        bean27.setName("方世玉");

        ContactEntity bean28 = new ContactEntity();
        bean28.setName("高芳");

        ContactEntity bean29 = new ContactEntity();
        bean29.setName("海大富");

        ContactEntity bean30 = new ContactEntity();
        bean30.setName("江离");

        ContactEntity bean31 = new ContactEntity();
        bean31.setName("康辉");

        ContactEntity bean32 = new ContactEntity();
        bean32.setName("牛郎");

        ContactEntity bean33 = new ContactEntity();
        bean33.setName("谢天华");

        ContactEntity bean34 = new ContactEntity();
        bean34.setName("单雄心");

        ContactEntity bean35 = new ContactEntity();
        bean35.setName("赛华佗");

        list.add(bean1);
        list.add(bean2);
        list.add(bean3);
        list.add(bean4);
        list.add(bean5);
        list.add(bean6);
        list.add(bean7);
        list.add(bean8);
        list.add(bean9);
        list.add(bean10);
        list.add(bean11);
        list.add(bean12);
        list.add(bean13);
        list.add(bean14);
        list.add(bean15);
        list.add(bean16);
        list.add(bean17);
        list.add(bean18);
        list.add(bean19);
        list.add(bean20);
        list.add(bean21);
        list.add(bean22);
        list.add(bean23);
        list.add(bean24);
        list.add(bean25);
        list.add(bean26);
        list.add(bean27);
        list.add(bean28);
        list.add(bean29);
        list.add(bean30);
        list.add(bean31);
        list.add(bean32);
        list.add(bean33);
        list.add(bean34);
        list.add(bean35);

        SortUtil.sortByLetter(list);

        mContactAdapter = new ContactAdapter(list);
        mList.setAdapter(mContactAdapter);
    }

    @Override
    public void onTouch(String s) {
        mLetterWindow.show(s);
        int index = mContactAdapter.getSectionIndex(s);
        int position = mContactAdapter.getPositionForSection(index);
        if (position != -1)
            mList.setSelection(position);
    }

    @Override
    public void onLetterChanged(String preLetter, String letter) {
        mLetterWindow.update(letter);
        int index = mContactAdapter.getSectionIndex(letter);
        int position = mContactAdapter.getPositionForSection(index);
        if (position != -1)
            mList.setSelection(position);
    }

    @Override
    public void onRelease() {
        mLetterWindow.hide();
    }
}

activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    android:orientation="vertical">

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1">

        <ListView
            android:id="@+id/list"
            style="@style/CustomList"
            android:visibility="gone"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />

        <com.mjc.contactlistdemo.sort_by_letter.IndexView
            android:id="@+id/civ"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_gravity="right" />
    </FrameLayout>
</LinearLayout>

以上就是使用的过程,还是很简便的。

到这里,这个字母索引排序就算是写完了,谢谢!

时间: 2024-09-28 06:09:20

联系人列表字母排序索引(三)的相关文章

Android带索引联系人列表

网上Android联系人列表的样例也非常多,都和微信的联系人差点儿相同,因为项目用到了联系人列表索引功能(产品把字母item给去掉了),只是也还是好实现.这里我也来分享分享我的实现,免得以后忘了.那先看看效果(Demo在结尾有下载地址): 要达到的效果就是这么简单. 先说说思路吧:首先为联系人对象加入一个pinyin字段,当获取到了联系人原始数据后,把每一个联系人的名字转换为拼音.并为pinyin字段设置值. 然后获取联系人中出现过哪些字母的拼音保存为数组(这就是字母的item),然后和联系人拼

Android 联系人字母排序(仿微信)

现在很多APP只要涉及到联系人的界面,几乎都会采取字母排序以及导航的方式.作为程序猿,这种已经普及的需求还是需要学习的,于是小生开始了在网上默默的学习之路,网上学习的资料质量参差不齐,不过也有很不错的文章,文章后面分享给大家.这篇文章,仅是小生在学习之后,自己独立编写与总结吧.废话不多说先上效果图. 从界面上看,整个实现效果有两个重点: 实现字母分类. 实现右侧的字母导航. 我们先一个一个来了解解决方案,再上代码. 实现字母分类: 字母分类又分为三个小要点:一个是将中文转化为拼音,一个是实现按照

如何获取android手机联系人并按字母展示(三)

如果获取contact的头像信息并展示: 如何根据photoId来获取bitmap: public static Bitmap getContactPhoto(Context context, long photoId, BitmapFactory.Options options) { if (photoId < 0) { return null; } Cursor cursor = null; try { cursor = context.getContentResolver().query(

仿IOS通讯录效果,实现获取手机通讯录、字母排序显示、搜索联系人、拨打电话

1.使用UITableView,实现联系人字母排序.点击字母跳转显示联系人组目录: 2.使用UISearchController,实现联系搜索,动态显示符合查询的联系人: 3.点击通讯录列表项,显示联系人信息(使用自定义模式化窗口类似与UIAlertView,使用UIwindow实现),点击拨号,可以直接拨打电话: 4.实现获取手机通讯录里面的联系人信息: 详情见资源:http://download.csdn.net/detail/u011622479/9505751 效果图如下: 获取联系人:

带中文索引的ListView 仿微信联系人列表

由于各种原因,项目经理和产品经理把我做的东西给否定了,所以决定分享出去. 主要功能: 1 .带中文索引的ListView 2.自定义顶部搜索视图,可以对返回按钮,搜索按钮添加事件监听,带动画的咧!~ 3.底部自定义视图,可以对Listview的adapter添加监听,并且回调选中的数目,另外其他的视图都是可以自己添加的 4.右侧的索引视图,根据通讯录的解析后的数据动态生成相关索引列表 5.Adapter的抽象类,想优化自己的Adapter可以看一下,例子中的adapter仅仅是特例特写. 6.分

列表按照字母排序检索SideBar

项目中要求列表按照ABCD这种字母排序检索的功能,看了大神写的,瞬间崇拜了,接下来借大家参考参考了 首先是自定义view sidebar 1 /** 2 * @author J 3 *一个自定义view 实现a-z的竖直绘制,和监听滑动事件 4 */ 5 public class SideBar extends View { 6 private OnTouchingLetterChangedListener onTouchingLetterChangedListener; 7 public st

用ItemDecoration实现按字母排序列表

首先看看实现的效果 可以看出要实现上面效果,有三个步骤: 1.汉字转化为拼音,并且根据首字母排序 2.用ItemDecoration实现字母行的显示 3.自定义实现右侧的按字母导航栏 当然重点讲讲ItemDecoration的实现.都知道RecyclerView本身都没有分割线,需要分割线都是在item中画一条线或者使用ItemDecoration来实现分割线.在RecyclerView中我们可以给每一个item都添加ItemDecoration,所以可以自定义ItemDecoration来实现

Android 实现ListView的A-Z字母排序和过滤搜索功能,实现汉字转成拼音

转载请注明出处:http://blog.csdn.net/xiaanming/article/details/12684155 前段时间因为换工作的缘故又恰巧碰到国庆节,所以有段时间自己没有更新博客了,过完国庆到新公司报道,感觉还不错,就是现在住的地方离新公司有点远,地铁20站,伤不起啊,我每天早上7点多就要起床,然后屁颠屁颠的去挤地铁上班,晚上下班还要挤地铁,先不说路程远,车费一天就要10几块,我的银子啊,有坐龙华线去上班的深圳程序员不?听说那条线上班高峰期很挤?我没在上班高峰期坐过那趟车,我

安卓用QuickContactBadge和AsyncQueryHandler实现联系人列表的完美实现

打造你自己的个性联系人列表 在公司开发这么久了,发现好多的控件没有用过,然后发现了一些新的知识感觉还是很不错的,今天在这里我就来用一下QuickContactBadge的控件和AsyncQueryHandler,说到底QuickContactBadge这个控件我也是偶然发现的,然后乘着现在公司的工作不忙,然后也准备换工作温习一下知识点罢了. 一.介绍QuickContactBadge用法 1.  先看一下它的结构 <div style="text-align: justify;"