Android仿微信添加联系人列表,内附有截图和demo源码

最新demo地址,仿微信添加联系人WXAddPersonDemo

分享一个Android仿微信选择联系人页面

之前做的App主要是工具类的,而且公司的产品经理也喜欢在App里设计很多自定义控件,所以比一般市场上的App要麻烦一些,今天先介绍一个仿微信选择联系人的页面,涉及的功能较多

页面实现了哪些功能

  1. 将联系人名字首字母进行a-z排序,并且每一个字母都有一个头部,没有获取首字母的则放入#分类中,并且在a前面加入一个常用联系人展示
  2. 在列表右边有一列从 常、a-z、#可以快速索引
  3. 搜索功能,这里是搜索本地存储的联系人数据,而不是通过网络接口搜索
  4. 联系人列表可选中,并且反选可取消选中,选中的联系人头像显示搜索框中,点击框中头像取消选中
  5. 本地搜索支持对标题(联系人名字)和内容,汉字(或数字),首字母,全拼音,简拼音搜索
  6. 搜索列表和联系人列表界面类似,搜索列表对对搜索内容高亮显示,选中也加入头像到搜素框显示
  7. 搜索框动态处理了头部的宽度,当达到一定宽度时可滑动,实现效果在本文最后
有不懂的地方可以在下方评论区评论

实现效果如下

在这里插入图片描述
在这里插入图片描述

实现原理

1、快速索引栏,通过画步和画笔实现,里面、常、a-z、#是可以固定在里面也可以在获取后台数据排好序之后动态显示,例如排序之后没有常用联系人,可不显示常。通过重写view的dispatchTouchEvent方法控制触摸事件,并回调给页面显示。

2、首先我们需要将从后台(我这里联系人是从后台获取的,也可取本地)获得的联系人name汉字转换为拼音,并且取首字母进行分类,这步是为了展示列表a-z。

compile 'com.github.promeg:tinypinyin:2.0.1'

3、这步是关键的一步,将第2步获取到的list,将list中所有的拼音进行初始化,这是耗时操作,考虑在子线程中运行,使用线程或intentService处理均可行,将name和content的,汉字首字母和所有汉字的首字母和所有汉字拼音和拼音总长度都处理出来,加入到新的集合,此集合中就包括刚刚我们所取得的四个属性,这里处理的作用是为了之后按汉字,首字母,全拼搜索时会用到。

4、将第2部取到的list,a-z排序规则,利用Collections.sort(sourceDateList, pinyinComparator);进行排序,在adapter中根据首字母ascii值取第一次出现首字母的位置排序列表,右侧快速导航栏,滑动时根据ASCII值判断首字母第一次出现的位置设置listview的位置。

5、当有条目选中时,搜索框头像使用recyclerView展示,我这里控制头像的宽度为屏幕宽度的1/8,让后根据recyclerView的条目数动态控制recyclerView的宽度,当条目数大于等于6时,则recyclerView宽度达到最大,可滑动。

6、监听搜索框,有数据输入时,一个新列表或无数据页面将覆盖之前联系人列表。搜索的内容传入CNPinyinIndexFactory中,也在子线程中运行将搜索的结果给页面,CNPinyinIndexFactory中根据关键字根据先匹配中文,再匹配首字母,再匹配全拼音的顺序进行匹配,没有就是无数据页面。

7、由于这里多加对content的匹配,所以匹配先匹配name,再匹配content,匹配完成之后返回两个字段的下标用于搜索列表高亮显示。这里的做法较为复杂,尤其是匹配全拼音的时候,所以这里建议用安卓数据库来实现,orlmite做本地搜索不错,可支持模糊,时间区段,或者自己写sql语句进行查询。

下面是代码块

主页(布局)、联系人列表、搜索列表,头部列表
package com.pcjz.lems.ui.workrealname.manageequipment;

import android.content.Context;
import android.content.Intent;
import android.os.Handler;
import android.os.Message;
import android.support.v4.content.ContextCompat;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.text.Editable;
import android.text.Html;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.util.DisplayMetrics;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.InputMethodManager;
import android.widget.AdapterView;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.RelativeLayout;
import android.widget.TextView;

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.loopj.android.http.AsyncHttpResponseHandler;
import com.pcjz.lems.R;
import com.pcjz.lems.business.base.BaseActivity;
import com.pcjz.lems.business.base.basebean.BaseData;
import com.pcjz.lems.business.base.basebean.BaseListData;
import com.pcjz.lems.business.common.utils.StringUtils;
import com.pcjz.lems.business.common.utils.TLog;
import com.pcjz.lems.business.common.view.SideBar;
import com.pcjz.lems.business.common.view.personlist.CharacterParser;
import com.pcjz.lems.business.common.view.personlist.PinyinComparator;
import com.pcjz.lems.business.config.AppConfig;
import com.pcjz.lems.business.constant.ResultStatus;
import com.pcjz.lems.business.constant.SysCode;
import com.pcjz.lems.business.context.AppContext;
import com.pcjz.lems.business.entity.PersonInfoEntity;
import com.pcjz.lems.business.storage.SharedPreferencesManager;
import com.pcjz.lems.business.webapi.MainApi;
import com.pcjz.lems.business.widget.contractlist.CNPinyin;
import com.pcjz.lems.business.widget.contractlist.CNPinyinFactory;
import com.pcjz.lems.business.widget.contractlist.CNPinyinIndex;
import com.pcjz.lems.business.widget.contractlist.CNPinyinIndexFactory;
import com.pcjz.lems.ui.workrealname.manageequipment.adapter.ContactsSortAdapter;
import com.pcjz.lems.ui.workrealname.manageequipment.adapter.SearchContractsAdapter;
import com.pcjz.lems.ui.workrealname.manageequipment.adapter.SearchHeaderAdapter;

import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.entity.StringEntity;
import org.json.JSONObject;

import java.io.Serializable;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * created by yezhengyu on 2017/9/19 11:21
 */

public class ChangePersonListActivity extends BaseActivity implements View.OnClickListener {

    private SideBar sideBar;
    private TextView dialog;
    ListView mListView;
    private ContactsSortAdapter contactsSortadapter;
    public static final int MSG_INITS_RESULTS = 0x0000;
    public static final int MSG_SEARCH_RESULTS = 0x0001;

    /**
     * 汉字转换成拼音的类
     */
    private CharacterParser characterParser;
    private List<PersonInfoEntity> sourceDateList;
    /**
     * 根据拼音来排列ListView里面的数据类
     */
    private PinyinComparator pinyinComparator;
    private EditText mEtSearch;
    private List<CNPinyinIndex<PersonInfoEntity>> filterDataList = new ArrayList<>();
    private ListView mSearchListView;
    private TextView mTvNoData;
    private SearchContractsAdapter searchContractsAdapter;
    private ArrayList<CNPinyin<PersonInfoEntity>> mCnPinyinArrayList;
    private LinearLayout mLlSearchResults;
    private String edittext;
    private List<PersonInfoEntity> mSearchHeaderList = new ArrayList<>();
    private RecyclerView mRecyclerView;
    private ImageView mIvSearchIcon;
    private RelativeLayout rlNoData;
    private ImageView ivNoData;
    private TextView tvNoData;
    private SearchHeaderAdapter searchHeaderAdapter;
    private int width;
    private int height;
    private String mLargeDeviceId;

    private String mUserId;
    private String mProjectId;
    private ArrayList<PersonInfoEntity> mPersonDatas;
    private LinearLayout mLayout;
    private RelativeLayout mRlBack;
    private TextView mTvTitleBarRight;

    @Override
    public void setView() {
        setContentView(R.layout.activity_change_person);
        setTitle(AppContext.mResource.getString(R.string.modify_person_list));
        DisplayMetrics dm = getResources().getDisplayMetrics();
        width = dm.widthPixels;
        height = dm.heightPixels;
    }

    @Override
    protected void setBack() {
        mRlBack.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                closeKeyboard();
                finish();
            }
        });
    }

    @Override
    protected void initView() {
        mRlBack = (RelativeLayout) findViewById(R.id.rl_back);
        mTvTitleBarRight = (TextView) findViewById(R.id.tv_titlebar_right);
        mTvTitleBarRight.setText(R.string.modify_person_finish);
        RelativeLayout rlFinish = (RelativeLayout) findViewById(R.id.rl_my_download);
        rlFinish.setOnClickListener(this);
        mLargeDeviceId = getIntent().getExtras().getString("largeDeviceId");
        mPersonDatas = (ArrayList<PersonInfoEntity>) getIntent().getSerializableExtra("personDatas");
        sideBar = (SideBar) findViewById(R.id.sidrbar);
        dialog = (TextView) findViewById(R.id.dialog);
        sideBar.setTextView(dialog);
        mUserId = SharedPreferencesManager.getString(ResultStatus.USER_ID);
        mProjectId = SharedPreferencesManager.getString(mUserId + SysCode.PROJECTPERIODID);
        mListView = (ListView) findViewById(R.id.lv_contacts);
        //搜索图标
        mIvSearchIcon = (ImageView) findViewById(R.id.iv_search_icon);
        //搜索recyclerView
        mRecyclerView = (RecyclerView) findViewById(R.id.recyclerview_header);
        LinearLayoutManager layoutManager = new LinearLayoutManager(this);
        layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
        mRecyclerView.setLayoutManager(layoutManager);
        //搜索editText
        mEtSearch = (EditText) findViewById(R.id.et_search_person);
        //搜索记录布局
        mLlSearchResults = (LinearLayout) findViewById(R.id.ll_search_results);
        //搜索记录
        mSearchListView = (ListView) findViewById(R.id.lv_search_contacts);

        //无数据页面
        mLayout = (LinearLayout) findViewById(R.id.ll_content);
        mLayout.setVisibility(View.GONE);
        //没有搜索记录时
        mTvNoData = (TextView) findViewById(R.id.tv_no_search_data);
        rlNoData = (RelativeLayout) findViewById(R.id.rl_no_data);
        ivNoData = (ImageView) findViewById(R.id.iv_no_data);
        tvNoData = (TextView) findViewById(R.id.tv_no_data);
        initNoDataView();

        //实例化汉字转拼音类
        characterParser = CharacterParser.getInstance();
        pinyinComparator = new PinyinComparator();

        //搜索记录listView
        searchContractsAdapter = new SearchContractsAdapter(this, filterDataList);
        mSearchListView.setAdapter(searchContractsAdapter);
        //搜索头部添加recyclerView
        searchHeaderAdapter = new SearchHeaderAdapter(this, mSearchHeaderList, width);
        mRecyclerView.setAdapter(searchHeaderAdapter);

        requestContractData();
    }

    private void requestContractData() {
        initLoading("");
        JSONObject obj = new JSONObject();
        HttpEntity entity = null;
        try {
            JSONObject obj0 = new JSONObject();
            obj.put("projectId", mProjectId);
            obj.put("largeDeviceId", mLargeDeviceId);
            obj0.put("params", obj);
            entity = new StringEntity(obj0.toString(), "UTF-8");
        } catch (Exception e) {
            e.printStackTrace();
            return;
        }
        MainApi.requestCommon(this, AppConfig.GET_LARGE_EQUIPMENT_BIND_WORK_MECHINE_PERSONS, entity, new AsyncHttpResponseHandler() {
            @Override
            public void onSuccess(int i, Header[] headers, byte[] bytes) {
                hideLoading();
                try {
                    String httpResult = new String(bytes);
                    TLog.log("getChangePersonList : " + httpResult);
                    Type type = new TypeToken<BaseListData<PersonInfoEntity>>() {
                    }.getType();
                    BaseListData<PersonInfoEntity> datas = new Gson().fromJson(httpResult, type);
                    if (StringUtils.equals(datas.getCode(), ResultStatus.SUCCESS)) {
                        List<PersonInfoEntity> personList = datas.getData();
                        if (personList != null && personList.size() != 0) {
                            if (mTvTitleBarRight.getVisibility() != View.VISIBLE) {
                                mTvTitleBarRight.setVisibility(View.VISIBLE);
                            }
                            if (mLayout != null && mLayout.getVisibility() != View.VISIBLE) {
                                mLayout.setVisibility(View.VISIBLE);
                            }
                            if (rlNoData != null && rlNoData.getVisibility() == View.VISIBLE) {
                                rlNoData.setVisibility(View.GONE);
                            }
                            sourceDateList = filledData(personList);
                            //集合中所有拼音的初始化,考虑在子线程中运行
                            CNPinyinFactory.createCNPinyinList(sourceDateList, MSG_INITS_RESULTS, mHandler);
                            // 根据a-z进行排序源数据
                            Collections.sort(sourceDateList, pinyinComparator);
                            mPersonDatas.remove(mPersonDatas.size()-1);
                            //列表listView
                            contactsSortadapter = new ContactsSortAdapter(ChangePersonListActivity.this, sourceDateList, mPersonDatas);
                            mListView.setAdapter(contactsSortadapter);
                            initHeadList();
                        } else {
                            initNoData();
                        }
                        return;
                    } else {
                        initNoData();
                        AppContext.showToast(datas.getMsg());
                        return;
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
                initNoData();
            }

            @Override
            public void onFailure(int i, Header[] headers, byte[] bytes, Throwable throwable) {
                hideLoading();
                initNoInternetView();
            }
        });
    }

    //有网无数据
    private void initNoDataView() {
        if (ivNoData == null) return;
        rlNoData.setBackground(ContextCompat.getDrawable(this, R.color.white));
        ivNoData.setImageResource(R.drawable.pop_window_choose_no_content);
        tvNoData.setText(AppContext.mResource.getString(R.string.person_list_no_data));
    }

    //网络异常
    private void initNoInternetView() {
        if (ivNoData == null) return;
        ivNoData.setImageResource(R.drawable.no_internet_icon);
        tvNoData.setText(AppContext.mResource.getString(R.string.please_check_network));
        if (mTvTitleBarRight.getVisibility() == View.VISIBLE) {
            mTvTitleBarRight.setVisibility(View.GONE);
        }
    }

    private void initNoData() {
        if (rlNoData == null) return;
        if (rlNoData != null && rlNoData.getVisibility() != View.VISIBLE) {
            rlNoData.setVisibility(View.VISIBLE);
        }
        if (mLayout != null && mLayout.getVisibility() == View.VISIBLE) {
            mLayout.setVisibility(View.GONE);
        }
        if (mTvTitleBarRight.getVisibility() == View.VISIBLE) {
            mTvTitleBarRight.setVisibility(View.GONE);
        }
    }

    @Override
    public void setListener() {
        // 设置右侧[A-Z]快速导航栏触摸监听
        sideBar.setOnTouchingLetterChangedListener(new SideBar.OnTouchingLetterChangedListener() {

            @Override
            public void onTouchingLetterChanged(String s) {
                if (contactsSortadapter != null && mListView != null) {
                    //by yezhengyu
                    /*if (StringUtils.equals(s, "#")) {
                        mListView.setSelection(sourceDateList.size() - 1);
                        return;
                    }*/

                    // 该字母首次出现的位置
                    int position = contactsSortadapter.getPositionForSection(s.charAt(0));
                    if (position != -1) {
                        mListView.setSelection(position);
                    }
                }
            }
        });
        // item事件
        mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {

            @Override
            public void onItemClick(AdapterView<?> adapterView, View view, int position, long arg3) {
                ContactsSortAdapter.ViewHolder viewHolder = (ContactsSortAdapter.ViewHolder) view.getTag();
                viewHolder.cbChecked.performClick();
                contactsSortadapter.toggleChecked(position);
                initHeadList();
            }
        });

        mEtSearch.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {

            }

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {

            }

            @Override
            public void afterTextChanged(Editable s) {
                if (s.length() > 0) {
                    edittext = s.toString();
                    mLlSearchResults.setVisibility(View.VISIBLE);
                    //搜索考虑在子线程中运行
                    CNPinyinIndexFactory.indexList(mCnPinyinArrayList, s.toString(), MSG_SEARCH_RESULTS, mHandler);
                } else {
                    mLlSearchResults.setVisibility(View.GONE);
                }
            }
        });

        mSearchListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                SearchContractsAdapter.ViewHolder viewHolder = (SearchContractsAdapter.ViewHolder) view.getTag();
                viewHolder.cbChecked.performClick();
                searchContractsAdapter.toggleChecked(position);
                List<PersonInfoEntity> searchSelectedList = searchContractsAdapter.getSelectedList();
                contactsSortadapter.updateListView(searchSelectedList);
                mLlSearchResults.setVisibility(View.GONE);
                mEtSearch.setText("");
                initHeadList();
            }
        });

        //头像点击删除
        searchHeaderAdapter.setOnItemClickListener(new SearchHeaderAdapter.OnClickLisenerI() {
            @Override
            public void setOnClickListener(View view, int position) {
                mSearchHeaderList.remove(position);
                contactsSortadapter.updateListView(mSearchHeaderList);
                initHeadList();
                if (mLlSearchResults != null && mLlSearchResults.getVisibility() == View.VISIBLE) {
                    if (mSearchListView != null && mSearchListView.getVisibility() == View.VISIBLE) {
                        searchContractsAdapter.updateListView2(mSearchHeaderList);
                    }
                }
            }
        });
    }

    private void initHeadList() {
        List<PersonInfoEntity> contactsSelectedList = contactsSortadapter.getSelectedList();
        if (contactsSelectedList.size() > 0) {
            mIvSearchIcon.setVisibility(View.GONE);
            mRecyclerView.setVisibility(View.VISIBLE);
            mSearchHeaderList.clear();
            mSearchHeaderList.addAll(contactsSelectedList);
            searchHeaderAdapter.notifyDataSetChanged();
            int itemCount = searchHeaderAdapter.getItemCount();
            ViewGroup.LayoutParams layoutParams = mRecyclerView.getLayoutParams();
            if (itemCount >= 6) {
                layoutParams.width = 3 * width / 4;
            } else {
                layoutParams.width = LinearLayout.LayoutParams.WRAP_CONTENT;
            }
            mRecyclerView.setLayoutParams(layoutParams);
            mRecyclerView.scrollToPosition(itemCount - 1);
        } else {
            mIvSearchIcon.setVisibility(View.VISIBLE);
            mRecyclerView.setVisibility(View.GONE);
        }
    }

    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            int what = msg.what;
            switch (what) {
                case MSG_INITS_RESULTS:
                    mCnPinyinArrayList = (ArrayList<CNPinyin<PersonInfoEntity>>) msg.obj;
                    break;
                case MSG_SEARCH_RESULTS:
                    ArrayList<CNPinyinIndex<PersonInfoEntity>> cnPinyinIndexArrayList = (ArrayList<CNPinyinIndex<PersonInfoEntity>>) msg.obj;
                    if (cnPinyinIndexArrayList != null && cnPinyinIndexArrayList.size() != 0) {
                        if (mSearchListView != null && mSearchListView.getVisibility() == View.GONE) {
                            mSearchListView.setVisibility(View.VISIBLE);
                        }
                        if (mTvNoData != null && mTvNoData.getVisibility() == View.VISIBLE) {
                            mTvNoData.setVisibility(View.GONE);
                        }

                        List<PersonInfoEntity> contactSelectedList = contactsSortadapter.getSelectedList();
                        searchContractsAdapter.updateListView(cnPinyinIndexArrayList, contactSelectedList);
                    } else {
                        if (mSearchListView != null && mSearchListView.getVisibility() == View.VISIBLE) {
                            mSearchListView.setVisibility(View.GONE);
                        }
                        if (mTvNoData != null && mTvNoData.getVisibility() == View.GONE) {
                            mTvNoData.setVisibility(View.VISIBLE);
                        }
                        mTvNoData.setText(Html.fromHtml("没有找到“" + "<font color='#FD9426' size='20'>" + edittext + "</font>" + "”相关的结果"));
                    }
                    break;
            }
        }
    };


    /**
     * 为ListView填充数据
     * @return
     */
    private List<PersonInfoEntity> filledData(List<PersonInfoEntity> personList) {
        List<PersonInfoEntity> mSortList = new ArrayList<PersonInfoEntity>();
        for (int i = 0; i < personList.size(); i++) {
            PersonInfoEntity sortModel = new PersonInfoEntity();
            PersonInfoEntity personInfo = personList.get(i);
            sortModel.setEmpName(personInfo.getEmpName());
            sortModel.setJobName(personInfo.getJobName());
            sortModel.setFacephoto(personInfo.getFacephoto());
            sortModel.setPersonId(personInfo.getPersonId());
            sortModel.setProjectPersonId(personInfo.getProjectPersonId());
            sortModel.setBackGroundColor(personInfo.getBackGroundColor());
            // 汉字转换成拼音
            String pinyin = characterParser.getSelling(personList.get(i).getEmpName());
            String sortString = pinyin.substring(0, 1).toUpperCase();

            // 正则表达式,判断首字母是否是英文字母
            if (sortString.matches("[A-Z]")) {
                sortModel.setSortLetters(sortString.toUpperCase());
            } else {
                sortModel.setSortLetters("#");
            }
            mSortList.add(sortModel);
        }
        return mSortList;
    }

    @Override
    public void onClick(View v) {
        int id = v.getId();
        switch (id) {
            case R.id.rl_my_download:
                List<PersonInfoEntity> contactsSelectedList = contactsSortadapter.getSelectedList();
                Intent intent = new Intent();
                intent.putExtra("personDatas", (Serializable)contactsSelectedList);
                this.setResult(1, intent);
                closeKeyboard();
                finish();
                break;
        }
    }

    @Override
    protected boolean hasLoading() {
        return true;
    }

    private void closeKeyboard() {
        View view = getWindow().peekDecorView();
        if (view != null) {
            InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
            inputMethodManager.hideSoftInputFromWindow(view.getWindowToken(), 0);
        }
    }
}

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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="match_parent"
        android:layout_height="match_parent"
        android:background="@color/white"
        android:orientation="vertical">

        <include layout="@layout/layout_titlebar_application" />

        <LinearLayout
            android:id="@+id/ll_content"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="60dp"
                android:orientation="horizontal">

                <ImageView
                    android:id="@+id/iv_search_icon"
                    android:layout_width="30dp"
                    android:layout_height="match_parent"
                    android:paddingBottom="20dp"
                    android:paddingLeft="10dp"
                    android:paddingTop="20dp"
                    android:src="@drawable/tz_search_icon" />

                <android.support.v7.widget.RecyclerView
                    android:id="@+id/recyclerview_header"
                    android:layout_width="wrap_content"
                    android:layout_height="60dp"
                    android:layout_centerVertical="true"
                    android:scrollbars="horizontal"
                    android:visibility="gone" />

                <EditText
                    android:id="@+id/et_search_person"
                    android:layout_width="match_parent"
                    android:layout_height="60dp"
                    android:background="@null"
                    android:hint="搜索"
                    android:paddingLeft="7dp"
                    android:textColorHint="@color/txt_gray_shallow"
                    android:textSize="15sp" />
            </LinearLayout>

            <View
                android:layout_width="match_parent"
                android:layout_height="1px"
                android:background="@color/txt_gray_divider" />

            <FrameLayout
                android:layout_width="fill_parent"
                android:layout_height="fill_parent">

                <ListView
                    android:id="@+id/lv_contacts"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:divider="@null"
                    android:scrollbars="none"
                    android:visibility="visible" />

                <TextView
                    android:id="@+id/dialog"
                    android:layout_width="80dp"
                    android:layout_height="80dp"
                    android:layout_gravity="center"
                    android:background="@drawable/shape_person_text_dialog"
                    android:gravity="center"
                    android:text=""
                    android:textColor="@color/white"
                    android:textSize="50dp"
                    android:visibility="invisible" />

                <com.pcjz.lems.business.common.view.SideBar
                    android:id="@+id/sidrbar"
                    android:layout_width="30dp"
                    android:layout_height="match_parent"
                    android:layout_gravity="right|center"
                    android:layout_marginBottom="20dp"
                    android:layout_marginTop="20dp" />

                <LinearLayout
                    android:id="@+id/ll_search_results"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:background="@color/white"
                    android:orientation="vertical"
                    android:visibility="gone">

                    <ListView
                        android:id="@+id/lv_search_contacts"
                        android:layout_width="match_parent"
                        android:layout_height="match_parent"
                        android:divider="@null"
                        android:scrollbars="none" />

                    <TextView
                        android:id="@+id/tv_no_search_data"
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:layout_marginTop="32dp"
                        android:gravity="center"
                        android:text=""
                        android:textColor="@color/txt_black"
                        android:textSize="14sp"
                        android:visibility="gone" />
                </LinearLayout>
            </FrameLayout>
        </LinearLayout>
        <include layout="@layout/layout_no_data" />
    </LinearLayout>

    <include layout="@layout/layout_loading" />
</RelativeLayout>
package com.pcjz.lems.ui.workrealname.manageequipment.adapter;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.drawable.GradientDrawable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.CheckBox;
import android.widget.SectionIndexer;
import android.widget.TextView;

import com.nostra13.universalimageloader.core.DisplayImageOptions;
import com.nostra13.universalimageloader.core.ImageLoader;
import com.nostra13.universalimageloader.core.assist.ImageScaleType;
import com.pcjz.lems.R;
import com.pcjz.lems.business.common.utils.StringUtils;
import com.pcjz.lems.business.common.view.CircleImageView;
import com.pcjz.lems.business.config.AppConfig;
import com.pcjz.lems.business.entity.PersonInfoEntity;

import java.util.ArrayList;
import java.util.List;
import java.util.Locale;


public class ContactsSortAdapter extends BaseAdapter implements SectionIndexer {
    private List<PersonInfoEntity> mList;
    private List<PersonInfoEntity> mSelectedList;
    private Context mContext;
    LayoutInflater mInflater;

    private DisplayImageOptions mOption = new DisplayImageOptions.Builder()
            .showImageOnLoading(R.drawable.load_pho_default_image)
            .showImageForEmptyUri(R.drawable.load_pho_default_image)
            .showImageOnFail(R.drawable.load_pho_default_image)
            .cacheInMemory(true)
            .cacheOnDisc(false).bitmapConfig(Bitmap.Config.RGB_565)
            .imageScaleType(ImageScaleType.EXACTLY).build();

    public ContactsSortAdapter(Context mContext, List<PersonInfoEntity> list, List<PersonInfoEntity> personDatas) {
        this.mContext = mContext;
        mSelectedList = new ArrayList<>();
        mSelectedList.addAll(personDatas);
        if (list == null) {
            this.mList = new ArrayList<>();
        } else {
            this.mList = list;
        }
    }

    /**
     * 当ListView数据发生变化时,调用此方法来更新ListView
     */
    public void updateListView(/*List<PersonInfoEntity> list*/List<PersonInfoEntity> selectedList) {
        /*if (list == null) {
			this.mList = new ArrayList<>();
		} else {
			this.mList = list;
		}*/
        mSelectedList.clear();
        mSelectedList.addAll(selectedList);
        notifyDataSetChanged();
    }

    public int getCount() {
        return this.mList.size();
    }

    public Object getItem(int position) {
        return mList.get(position);
    }

    public long getItemId(int position) {
        return position;
    }

    public View getView(final int position, View view, ViewGroup arg2) {
        ViewHolder viewHolder = null;
        final PersonInfoEntity mContent = mList.get(position);
        if (view == null) {
            viewHolder = new ViewHolder();
            view = LayoutInflater.from(mContext).inflate(R.layout.item_contact, null);
            viewHolder.tvTitle = (TextView) view.findViewById(R.id.tv_title_name);
            viewHolder.tvHeader = (TextView) view.findViewById(R.id.tv_person_header);
            viewHolder.ivHeader = (CircleImageView) view.findViewById(R.id.iv_person_header);
            viewHolder.tvCompany = (TextView) view.findViewById(R.id.tv_content_company);
            viewHolder.tvLetter = (TextView) view.findViewById(R.id.catalog);
            viewHolder.cbChecked = (CheckBox) view.findViewById(R.id.cbChecked);
            viewHolder.viewDivider = view.findViewById(R.id.view_divider);
            view.setTag(viewHolder);
        } else {
            viewHolder = (ViewHolder) view.getTag();
        }

        //根据position获取分类的首字母的Char ascii值
        int section = getSectionForPosition(position);

        //如果当前位置等于该分类首字母的Char的位置 ,则认为是第一次出现
        if (position == getPositionForSection(section)) {
            viewHolder.tvLetter.setVisibility(View.VISIBLE);
            viewHolder.viewDivider.setVisibility(View.VISIBLE);
            viewHolder.tvLetter.setText(mContent.getSortLetters());
        } else {
            viewHolder.tvLetter.setVisibility(View.GONE);
            viewHolder.viewDivider.setVisibility(View.GONE);
        }
        String name = this.mList.get(position).getEmpName();
        String backGroundColor = this.mList.get(position).getBackGroundColor();
        String facePhotoUrl = this.mList.get(position).getFacephoto();
        if (StringUtils.isEmpty(facePhotoUrl)) {
            viewHolder.tvHeader.setVisibility(View.VISIBLE);
            viewHolder.ivHeader.setVisibility(View.GONE);
            GradientDrawable myGrad = (GradientDrawable) viewHolder.tvHeader.getBackground();
            if (!StringUtils.isEmpty(backGroundColor)) {
                myGrad.setColor(Color.parseColor(backGroundColor));
            } else {
                myGrad.setColor(Color.parseColor("#38AFF7"));
            }
            if (!StringUtils.isEmpty(name) && name.length() >= 2) {
                viewHolder.tvHeader.setText(name.substring(name.length() - 2, name.length()));
            } else {
                viewHolder.tvHeader.setText(name);
            }
        } else {
            viewHolder.ivHeader.setVisibility(View.VISIBLE);
            viewHolder.tvHeader.setVisibility(View.GONE);
            ImageLoader.getInstance().displayImage(AppConfig.IMAGE_FONT_URL + facePhotoUrl, viewHolder.ivHeader, mOption);
        }
        viewHolder.tvTitle.setText(name);
        viewHolder.tvCompany.setText(this.mList.get(position).getJobName());
        viewHolder.cbChecked.setChecked(isSelected(mContent));

        return view;

    }

    public static class ViewHolder {
        public TextView tvLetter;
        public TextView tvTitle;
        public TextView tvHeader;
        public CircleImageView ivHeader;
        public TextView tvCompany;
        public CheckBox cbChecked;
        public View viewDivider;
    }

    /**
     * 根据ListView的当前位置获取分类的首字母的Char ascii值
     */
    public int getSectionForPosition(int position) {
        return mList.get(position).getSortLetters().charAt(0);
    }

    /**
     * 根据分类的首字母的Char ascii值获取其第一次出现该首字母的位置
     */
    public int getPositionForSection(int section) {
        for (int i = 0; i < getCount(); i++) {
            String sortStr = mList.get(i).getSortLetters();
            char firstChar = sortStr.toUpperCase(Locale.CHINESE).charAt(0);
            if (firstChar == section) {
                return i;
            }
        }
        return -1;
    }

    @Override
    public Object[] getSections() {
        return null;
    }

    private boolean isSelected(PersonInfoEntity model) {
        for (int i = 0; i < mSelectedList.size(); i++) {
            if (StringUtils.equals(mSelectedList.get(i).getPersonId(), model.getPersonId())) {
                return true;
            }
        }
        return false;
    }

    public void toggleChecked(int position) {
        if (isSelected(mList.get(position))) {
            removeSelected(position);
        } else {
            setSelected(position);
        }

    }

    private void setSelected(int position) {
        mSelectedList.add(mList.get(position));
    }

    private void removeSelected(int position) {
        for (int i = 0; i < mSelectedList.size(); i++) {
            if (StringUtils.equals(mSelectedList.get(i).getPersonId(), mList.get(position).getPersonId())) {
                mSelectedList.remove(mSelectedList.get(i));
                break;
            }
        }
    }

    public List<PersonInfoEntity> getSelectedList() {
        return mSelectedList;
    }
}
<?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:background="@color/white"
    android:orientation="vertical" >

    <TextView
        android:id="@+id/catalog"
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:paddingLeft="15dp"
        android:gravity="center_vertical"
        android:textColor="@color/txt_gray"
        android:textSize="15sp" />

    <View
        android:id="@+id/view_divider"
        android:layout_width="match_parent"
        android:layout_height="1px"
        android:background="@color/txt_gray_divider"/>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:gravity="center_vertical"
        android:orientation="horizontal"
        android:paddingLeft="15dp" >

        <CheckBox
            android:id="@+id/cbChecked"
            android:layout_width="17dp"
            android:layout_height="17dp"
            android:background="@drawable/selector_checkbox_contact"
            android:button="@null"
            android:clickable="false"
            android:focusable="false"
            android:visibility="visible" />

        <TextView
            android:id="@+id/tv_person_header"
            android:layout_width="36dp"
            android:layout_height="36dp"
            android:layout_marginLeft="13dp"
            android:background="@drawable/shape_circle_person_header"
            android:text="三丰"
            android:gravity="center"
            android:textSize="12sp"
            android:textColor="@color/white"
            />

        <com.pcjz.lems.business.common.view.CircleImageView
            android:id="@+id/iv_person_header"
            android:layout_width="36dp"
            android:layout_height="36dp"
            android:layout_marginLeft="13dp"
            android:src="@mipmap/ic_launcher"
            android:visibility="gone"/>

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent" >

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:gravity="center_vertical"
                android:orientation="horizontal">
            <TextView
                android:id="@+id/tv_title_name"
                android:layout_width="0dp"
                android:layout_weight="1"
                android:layout_height="wrap_content"
                android:layout_alignParentLeft="true"
                android:layout_marginLeft="13dp"
                android:singleLine="true"
                android:textColor="@color/txt_black"
                android:textSize="15sp"
                android:text="李超勤"/>

            <TextView
                android:id="@+id/tv_content_company"
                android:layout_width="0dp"
                android:layout_weight="2"
                android:layout_height="wrap_content"
                android:paddingRight="20dp"
                android:singleLine="true"
                android:textColor="@color/txt_black"
                android:textSize="12sp"
                android:text="上城建筑科技有限公司项目部"/>
            </LinearLayout>
            <View
                android:layout_width="match_parent"
                android:layout_height="1px"
                android:layout_alignParentBottom="true"
                android:layout_marginLeft="13dp"
                android:background="@color/txt_gray_divider"/>
        </RelativeLayout>
    </LinearLayout>
</LinearLayout>
package com.pcjz.lems.ui.workrealname.manageequipment.adapter;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.drawable.GradientDrawable;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.style.ForegroundColorSpan;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.CheckBox;
import android.widget.TextView;

import com.nostra13.universalimageloader.core.DisplayImageOptions;
import com.nostra13.universalimageloader.core.ImageLoader;
import com.nostra13.universalimageloader.core.assist.ImageScaleType;
import com.pcjz.lems.R;
import com.pcjz.lems.business.common.utils.StringUtils;
import com.pcjz.lems.business.common.view.CircleImageView;
import com.pcjz.lems.business.config.AppConfig;
import com.pcjz.lems.business.entity.PersonInfoEntity;
import com.pcjz.lems.business.widget.contractlist.CNPinyinIndex;

import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

/**
 * created by yezhengyu on 2017/9/19 18:59
 */

public class SearchContractsAdapter extends BaseAdapter {
    private List<CNPinyinIndex<PersonInfoEntity>> mList;
    private List<PersonInfoEntity> mSelectedList;
    private Context mContext;

    private DisplayImageOptions mOption = new DisplayImageOptions.Builder()
            .showImageOnLoading(R.drawable.load_pho_default_image)
            .showImageForEmptyUri(R.drawable.load_pho_default_image)
            .showImageOnFail(R.drawable.load_pho_default_image)
            .cacheInMemory(true)
            .cacheOnDisc(false).bitmapConfig(Bitmap.Config.RGB_565)
            .imageScaleType(ImageScaleType.EXACTLY).build();

    public SearchContractsAdapter(Context mContext, List<CNPinyinIndex<PersonInfoEntity>> list) {
        this.mContext = mContext;
        mSelectedList = new ArrayList<>();
        this.mList = list;
    }

    /**
     * 当ListView数据发生变化时,调用此方法来更新ListView
     */
    public void updateListView(List<CNPinyinIndex<PersonInfoEntity>> newDatas, List<PersonInfoEntity> contactSelectedList) {
        this.mList.clear();
        this.mList.addAll(newDatas);
        mSelectedList.clear();
        mSelectedList.addAll(contactSelectedList);
        notifyDataSetChanged();
    }

    public void updateListView2(List<PersonInfoEntity> contactSelectedList) {
        mSelectedList.clear();
        mSelectedList.addAll(contactSelectedList);
        notifyDataSetChanged();
    }

    public int getCount() {
        return this.mList.size();
    }

    public Object getItem(int position) {
        return mList.get(position);
    }

    public long getItemId(int position) {
        return position;
    }

    public View getView(final int position, View view, ViewGroup arg2) {
        ViewHolder viewHolder = null;
        CNPinyinIndex<PersonInfoEntity> cnPinyinIndex = mList.get(position);
        PersonInfoEntity personInfo = cnPinyinIndex.cnPinyin.data;
        if (view == null) {
            viewHolder = new ViewHolder();
            view = LayoutInflater.from(mContext).inflate(R.layout.item_contact, null);
            viewHolder.tvTitle = (TextView) view.findViewById(R.id.tv_title_name);
            viewHolder.tvHeader = (TextView) view.findViewById(R.id.tv_person_header);
            viewHolder.ivHeader = (CircleImageView) view.findViewById(R.id.iv_person_header);
            viewHolder.tvCompany = (TextView) view.findViewById(R.id.tv_content_company);
            viewHolder.tvLetter = (TextView) view.findViewById(R.id.catalog);
            viewHolder.cbChecked = (CheckBox) view.findViewById(R.id.cbChecked);
            viewHolder.viewDivider = view.findViewById(R.id.view_divider);
            view.setTag(viewHolder);
        } else {
            viewHolder = (ViewHolder) view.getTag();
        }
        viewHolder.tvLetter.setVisibility(View.GONE);
        viewHolder.viewDivider.setVisibility(View.GONE);
        String name = personInfo.getEmpName();
        String backGroundColor = personInfo.getBackGroundColor();
        String facePhotoUrl = personInfo.getFacephoto();
        if (StringUtils.isEmpty(facePhotoUrl)) {
            viewHolder.tvHeader.setVisibility(View.VISIBLE);
            viewHolder.ivHeader.setVisibility(View.GONE);
            GradientDrawable myGrad = (GradientDrawable) viewHolder.tvHeader.getBackground();
            if (!StringUtils.isEmpty(backGroundColor)) {
                myGrad.setColor(Color.parseColor(backGroundColor));
            } else {
                myGrad.setColor(Color.parseColor("#38AFF7"));
            }
            if (!StringUtils.isEmpty(name) && name.length() >= 2) {
                viewHolder.tvHeader.setText(name.substring(name.length() - 2, name.length()));
            } else {
                viewHolder.tvHeader.setText(name);
            }
        } else {
            viewHolder.ivHeader.setVisibility(View.VISIBLE);
            viewHolder.tvHeader.setVisibility(View.GONE);
            ImageLoader.getInstance().displayImage(AppConfig.IMAGE_FONT_URL + facePhotoUrl, viewHolder.ivHeader, mOption);
        }
        int startText = cnPinyinIndex.startText;
        int endText = cnPinyinIndex.endText;
        int startContent = cnPinyinIndex.startContent;
        int endContent = cnPinyinIndex.endContent;
        if (endText != 0 && endText >= startText) {
            SpannableStringBuilder ssb = new SpannableStringBuilder(personInfo.chineseText());
            ForegroundColorSpan span = new ForegroundColorSpan(Color.parseColor("#FD9426"));
            ssb.setSpan(span, startText, endText, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
            viewHolder.tvTitle.setText(ssb);
        } else {
            viewHolder.tvTitle.setText(name);
        }
        if (endContent != 0 && endContent >= startContent) {
            SpannableStringBuilder ssb1 = new SpannableStringBuilder(personInfo.chineseContent());
            ForegroundColorSpan span1 = new ForegroundColorSpan(Color.parseColor("#FD9426"));
            ssb1.setSpan(span1, startContent, endContent, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
            viewHolder.tvCompany.setText(ssb1);
        } else {
            viewHolder.tvCompany.setText(personInfo.getJobName());
        }
        viewHolder.cbChecked.setChecked(isSelected(personInfo));
        return view;
    }

    public static class ViewHolder {
        public TextView tvLetter;
        public TextView tvTitle;
        public TextView tvHeader;
        public CircleImageView ivHeader;
        public TextView tvCompany;
        public CheckBox cbChecked;
        public View viewDivider;
    }

    private boolean isSelected(PersonInfoEntity personInfo) {
        for (int i = 0; i < mSelectedList.size(); i++) {
            if (StringUtils.equals(mSelectedList.get(i).getPersonId(), personInfo.getPersonId())) {
                return true;
            }
        }
        return false;
    }

    public void toggleChecked(int position) {
        PersonInfoEntity personInfo = mList.get(position).cnPinyin.data;
        if (isSelected(personInfo)) {
            removeSelected(personInfo);
        } else {
            setSelected(personInfo);
        }
    }

    private void setSelected(PersonInfoEntity personInfo) {
        mSelectedList.add(personInfo);
    }

    private void removeSelected(PersonInfoEntity personInfo) {
        for (int i = 0; i < mSelectedList.size(); i++) {
            if (StringUtils.equals(mSelectedList.get(i).getPersonId(), personInfo.getPersonId())) {
                mSelectedList.remove(mSelectedList.get(i));
                break;
            }
        }
    }

    public List<PersonInfoEntity> getSelectedList() {
        return mSelectedList;
    }
}
package com.pcjz.lems.ui.workrealname.manageequipment.adapter;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.drawable.GradientDrawable;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import com.nostra13.universalimageloader.core.DisplayImageOptions;
import com.nostra13.universalimageloader.core.ImageLoader;
import com.nostra13.universalimageloader.core.assist.ImageScaleType;
import com.pcjz.lems.R;
import com.pcjz.lems.business.common.utils.StringUtils;
import com.pcjz.lems.business.common.view.CircleImageView;
import com.pcjz.lems.business.config.AppConfig;
import com.pcjz.lems.business.entity.PersonInfoEntity;

import java.util.List;

/**
 * created by yezhengyu on 2017/9/18 16:58
 */

public class SearchHeaderAdapter extends RecyclerView.Adapter<SearchHeaderAdapter.MyViewHolder> {

    private final int width;
    private Context mContext;
    private List<PersonInfoEntity> mDatas;
    private LayoutInflater mInflater;

    private DisplayImageOptions mOption = new DisplayImageOptions.Builder()
            .showImageOnLoading(R.drawable.load_pho_default_image)
            .showImageForEmptyUri(R.drawable.load_pho_default_image)
            .showImageOnFail(R.drawable.load_pho_default_image)
            .cacheInMemory(true)
            .cacheOnDisc(false).bitmapConfig(Bitmap.Config.RGB_565)
            .imageScaleType(ImageScaleType.EXACTLY).build();

    public SearchHeaderAdapter(Context context, List<PersonInfoEntity> datas, int width) {
        this.mContext = context;
        this.mDatas = datas;
        mInflater = LayoutInflater.from(context);
        this.width = width;
    }

    @Override
    public int getItemCount() {
        return mDatas == null ? 0 : mDatas.size();
    }

    @Override
    public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = mInflater.inflate(R.layout.item_search_person, parent, false);
        ViewGroup.LayoutParams layoutParams = view.getLayoutParams();
        layoutParams.width = width / 8;
        view.setLayoutParams(layoutParams);
        MyViewHolder holder = new MyViewHolder(view);
        return holder;
    }

    @Override
    public void onBindViewHolder(final MyViewHolder holder, final int position) {
        String name = mDatas.get(position).getEmpName();
        String backGroundColor = mDatas.get(position).getBackGroundColor();
        String facePhotoUrl = mDatas.get(position).getFacephoto();
        if (StringUtils.isEmpty(facePhotoUrl)) {
            holder.tvPerson.setVisibility(View.VISIBLE);
            holder.ivHeader.setVisibility(View.GONE);
            GradientDrawable myGrad = (GradientDrawable) holder.tvPerson.getBackground();
            if (!StringUtils.isEmpty(backGroundColor)) {
                myGrad.setColor(Color.parseColor(backGroundColor));
            } else {
                myGrad.setColor(Color.parseColor("#38AFF7"));
            }
            String subtring = "";
            if (!StringUtils.isEmpty(name)) {
                if (name.length() > 1) {
                    subtring = name.substring(name.length() - 2, name.length());
                } else {
                    subtring = name;
                }
            }
            holder.tvPerson.setText(subtring);
        } else {
            holder.ivHeader.setVisibility(View.VISIBLE);
            holder.tvPerson.setVisibility(View.GONE);
            ImageLoader.getInstance().displayImage(AppConfig.IMAGE_FONT_URL + facePhotoUrl, holder.ivHeader, mOption);
        }
        holder.itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                onClickLisener.setOnClickListener(holder.itemView, position);
            }
        });
    }

    private OnClickLisenerI onClickLisener;

    public void setOnItemClickListener(OnClickLisenerI onClickLisener) {
        this.onClickLisener = onClickLisener;
    }

    public interface OnClickLisenerI{
        void setOnClickListener(View view, int position);
    }

    class MyViewHolder extends RecyclerView.ViewHolder {

        TextView tvPerson;
        CircleImageView ivHeader;

        public MyViewHolder(View itemView) {
            super(itemView);
            tvPerson = (TextView) itemView.findViewById(R.id.tv_person_header);
            ivHeader = (CircleImageView) itemView.findViewById(R.id.iv_person_header);
        }
    }
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="60dp"
    android:layout_height="60dp"
    android:orientation="vertical"
    android:gravity="center">
    <TextView
        android:id="@+id/tv_person_header"
        android:layout_width="36dp"
        android:layout_height="36dp"
        android:background="@drawable/shape_circle_person_header"
        android:text="三丰"
        android:gravity="center"
        android:textSize="12sp"
        android:textColor="@color/white"
        />

    <com.pcjz.lems.business.common.view.CircleImageView
        android:id="@+id/iv_person_header"
        android:layout_width="36dp"
        android:layout_height="36dp"
        android:visibility="gone"/>
</LinearLayout>
package com.pcjz.lems.business.common.view;

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.util.TypedValue;
import android.view.MotionEvent;
import android.view.View;
import android.widget.TextView;

/**
 * created by yezhengyu on 2017/9/19 14:10
 */

public class SideBar extends View {
    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);
    }

    // 26个字母
    public static String[] b = {"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 Paint paint2 = new Paint();

    private TextView mTextDialog;

    public void setTextView(TextView mTextDialog) {
        this.mTextDialog = mTextDialog;
    }

    /**
     * 重写这个方法
     */
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        // 获取焦点改变背景颜色.
        int height = getHeight();// 获取对应高度
        int width = getWidth(); // 获取对应宽度
        int singleHeight = height / b.length;// 获取每一个字母的高度

        for (int i = 0; i < b.length; i++) {
            paint.setColor(Color.parseColor("#999999"));
            paint.setTypeface(Typeface.DEFAULT_BOLD);
            paint.setAntiAlias(true);
            paint.setTextSize(dp2px(12));
            // x坐标等于中间-字符串宽度的一半.
            float xPos = width / 2 - paint.measureText(b[i]) / 2;
            float yPos = singleHeight * i + singleHeight;
            // 选中的状态
            if (i == choose) {
                paint.setColor(Color.parseColor("#ffffff"));
                paint.setFakeBoldText(true);
                paint2.setColor(Color.parseColor("#38AFF7"));
                canvas.drawCircle(width / 2, yPos - paint.measureText(b[i]) / 2, width / 3, paint2);
            }
            canvas.drawText(b[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() * b.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 < b.length) {
                        if (listener != null) {
                            listener.onTouchingLetterChanged(b[c]);
                        }
                        if (mTextDialog != null) {
                            mTextDialog.setText(b[c]);
                            mTextDialog.setVisibility(View.VISIBLE);
                        }
                        choose = c;
                        invalidate();
                    }
                }
                break;
        }
        return true;
    }

    private OnTouchingLetterChangedListener onTouchingLetterChangedListener;

    /**
     * 向外公开的方法
     */
    public void setOnTouchingLetterChangedListener(
            OnTouchingLetterChangedListener onTouchingLetterChangedListener) {
        this.onTouchingLetterChangedListener = onTouchingLetterChangedListener;
    }

    public interface OnTouchingLetterChangedListener {
        void onTouchingLetterChanged(String s);
    }

    private int dp2px(int dp) {
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, getResources().getDisplayMetrics());
    }
}

拼音相关的类
/*
 * Filename	CharacterParser.java
 * Company	�Ϻ�����-�ֶ��ֹ�˾��
 * @author	LuRuihui
 * @version	0.1
 */
package com.pcjz.lems.business.common.view.personlist;

/**
 * Java����ת��Ϊƴ��
 * 
 */
public class CharacterParser {
	private static int[] pyvalue = new int[] {-20319, -20317, -20304, -20295, -20292, -20283, -20265, -20257, -20242, -20230, -20051, -20036, -20032,
			-20026, -20002, -19990, -19986, -19982, -19976, -19805, -19784, -19775, -19774, -19763, -19756, -19751, -19746, -19741, -19739, -19728,
			-19725, -19715, -19540, -19531, -19525, -19515, -19500, -19484, -19479, -19467, -19289, -19288, -19281, -19275, -19270, -19263, -19261,
			-19249, -19243, -19242, -19238, -19235, -19227, -19224, -19218, -19212, -19038, -19023, -19018, -19006, -19003, -18996, -18977, -18961,
			-18952, -18783, -18774, -18773, -18763, -18756, -18741, -18735, -18731, -18722, -18710, -18697, -18696, -18526, -18518, -18501, -18490,
			-18478, -18463, -18448, -18447, -18446, -18239, -18237, -18231, -18220, -18211, -18201, -18184, -18183, -18181, -18012, -17997, -17988,
			-17970, -17964, -17961, -17950, -17947, -17931, -17928, -17922, -17759, -17752, -17733, -17730, -17721, -17703, -17701, -17697, -17692,
			-17683, -17676, -17496, -17487, -17482, -17468, -17454, -17433, -17427, -17417, -17202, -17185, -16983, -16970, -16942, -16915, -16733,
			-16708, -16706, -16689, -16664, -16657, -16647, -16474, -16470, -16465, -16459, -16452, -16448, -16433, -16429, -16427, -16423, -16419,
			-16412, -16407, -16403, -16401, -16393, -16220, -16216, -16212, -16205, -16202, -16187, -16180, -16171, -16169, -16158, -16155, -15959,
			-15958, -15944, -15933, -15920, -15915, -15903, -15889, -15878, -15707, -15701, -15681, -15667, -15661, -15659, -15652, -15640, -15631,
			-15625, -15454, -15448, -15436, -15435, -15419, -15416, -15408, -15394, -15385, -15377, -15375, -15369, -15363, -15362, -15183, -15180,
			-15165, -15158, -15153, -15150, -15149, -15144, -15143, -15141, -15140, -15139, -15128, -15121, -15119, -15117, -15110, -15109, -14941,
			-14937, -14933, -14930, -14929, -14928, -14926, -14922, -14921, -14914, -14908, -14902, -14894, -14889, -14882, -14873, -14871, -14857,
			-14678, -14674, -14670, -14668, -14663, -14654, -14645, -14630, -14594, -14429, -14407, -14399, -14384, -14379, -14368, -14355, -14353,
			-14345, -14170, -14159, -14151, -14149, -14145, -14140, -14137, -14135, -14125, -14123, -14122, -14112, -14109, -14099, -14097, -14094,
			-14092, -14090, -14087, -14083, -13917, -13914, -13910, -13907, -13906, -13905, -13896, -13894, -13878, -13870, -13859, -13847, -13831,
			-13658, -13611, -13601, -13406, -13404, -13400, -13398, -13395, -13391, -13387, -13383, -13367, -13359, -13356, -13343, -13340, -13329,
			-13326, -13318, -13147, -13138, -13120, -13107, -13096, -13095, -13091, -13076, -13068, -13063, -13060, -12888, -12875, -12871, -12860,
			-12858, -12852, -12849, -12838, -12831, -12829, -12812, -12802, -12607, -12597, -12594, -12585, -12556, -12359, -12346, -12320, -12300,
			-12120, -12099, -12089, -12074, -12067, -12058, -12039, -11867, -11861, -11847, -11831, -11798, -11781, -11604, -11589, -11536, -11358,
			-11340, -11339, -11324, -11303, -11097, -11077, -11067, -11055, -11052, -11045, -11041, -11038, -11024, -11020, -11019, -11018, -11014,
			-10838, -10832, -10815, -10800, -10790, -10780, -10764, -10587, -10544, -10533, -10519, -10331, -10329, -10328, -10322, -10315, -10309,
			-10307, -10296, -10281, -10274, -10270, -10262, -10260, -10256, -10254};
	public static String[] pystr = new String[] {"a", "ai", "an", "ang", "ao", "ba", "bai", "ban", "bang", "bao", "bei", "ben", "beng", "bi", "bian",
			"biao", "bie", "bin", "bing", "bo", "bu", "ca", "cai", "can", "cang", "cao", "ce", "ceng", "cha", "chai", "chan", "chang", "chao", "che",
			"chen", "cheng", "chi", "chong", "chou", "chu", "chuai", "chuan", "chuang", "chui", "chun", "chuo", "ci", "cong", "cou", "cu", "cuan",
			"cui", "cun", "cuo", "da", "dai", "dan", "dang", "dao", "de", "deng", "di", "dian", "diao", "die", "ding", "diu", "dong", "dou", "du",
			"duan", "dui", "dun", "duo", "e", "en", "er", "fa", "fan", "fang", "fei", "fen", "feng", "fo", "fou", "fu", "ga", "gai", "gan", "gang",
			"gao", "ge", "gei", "gen", "geng", "gong", "gou", "gu", "gua", "guai", "guan", "guang", "gui", "gun", "guo", "ha", "hai", "han", "hang",
			"hao", "he", "hei", "hen", "heng", "hong", "hou", "hu", "hua", "huai", "huan", "huang", "hui", "hun", "huo", "ji", "jia", "jian",
			"jiang", "jiao", "jie", "jin", "jing", "jiong", "jiu", "ju", "juan", "jue", "jun", "ka", "kai", "kan", "kang", "kao", "ke", "ken",
			"keng", "kong", "kou", "ku", "kua", "kuai", "kuan", "kuang", "kui", "kun", "kuo", "la", "lai", "lan", "lang", "lao", "le", "lei", "leng",
			"li", "lia", "lian", "liang", "liao", "lie", "lin", "ling", "liu", "long", "lou", "lu", "lv", "luan", "lue", "lun", "luo", "ma", "mai",
			"man", "mang", "mao", "me", "mei", "men", "meng", "mi", "mian", "miao", "mie", "min", "ming", "miu", "mo", "mou", "mu", "na", "nai",
			"nan", "nang", "nao", "ne", "nei", "nen", "neng", "ni", "nian", "niang", "niao", "nie", "nin", "ning", "niu", "nong", "nu", "nv", "nuan",
			"nue", "nuo", "o", "ou", "pa", "pai", "pan", "pang", "pao", "pei", "pen", "peng", "pi", "pian", "piao", "pie", "pin", "ping", "po", "pu",
			"qi", "qia", "qian", "qiang", "qiao", "qie", "qin", "qing", "qiong", "qiu", "qu", "quan", "que", "qun", "ran", "rang", "rao", "re",
			"ren", "reng", "ri", "rong", "rou", "ru", "ruan", "rui", "run", "ruo", "sa", "sai", "san", "sang", "sao", "se", "sen", "seng", "sha",
			"shai", "shan", "shang", "shao", "she", "shen", "sheng", "shi", "shou", "shu", "shua", "shuai", "shuan", "shuang", "shui", "shun",
			"shuo", "si", "song", "sou", "su", "suan", "sui", "sun", "suo", "ta", "tai", "tan", "tang", "tao", "te", "teng", "ti", "tian", "tiao",
			"tie", "ting", "tong", "tou", "tu", "tuan", "tui", "tun", "tuo", "wa", "wai", "wan", "wang", "wei", "wen", "weng", "wo", "wu", "xi",
			"xia", "xian", "xiang", "xiao", "xie", "xin", "xing", "xiong", "xiu", "xu", "xuan", "xue", "xun", "ya", "yan", "yang", "yao", "ye", "yi",
			"yin", "ying", "yo", "yong", "you", "yu", "yuan", "yue", "yun", "za", "zai", "zan", "zang", "zao", "ze", "zei", "zen", "zeng", "zha",
			"zhai", "zhan", "zhang", "zhao", "zhe", "zhen", "zheng", "zhi", "zhong", "zhou", "zhu", "zhua", "zhuai", "zhuan", "zhuang", "zhui",
			"zhun", "zhuo", "zi", "zong", "zou", "zu", "zuan", "zui", "zun", "zuo"};
	private StringBuilder buffer;
	private String resource;
	private static CharacterParser characterParser = new CharacterParser();

	public static CharacterParser getInstance() {
		return characterParser;
	}

	public String getResource() {
		return resource;
	}

	public void setResource(String resource) {
		this.resource = resource;
	}

	/** * ����ת��ASCII�� * * @param chs * @return */
	private int getChsAscii(String chs) {
		int asc = 0;
		try {
			byte[] bytes = chs.getBytes("gb2312");
			if (bytes == null || bytes.length > 2 || bytes.length <= 0) {
				throw new RuntimeException("illegal resource string");
			}
			if (bytes.length == 1) {
				asc = bytes[0];
			}
			if (bytes.length == 2) {
				int hightByte = 256 + bytes[0];
				int lowByte = 256 + bytes[1];
				asc = (256 * hightByte + lowByte) - 256 * 256;
			}
		} catch (Exception e) {
			System.out.println("ERROR:ChineseSpelling.class-getChsAscii(String chs)" + e);
		}
		return asc;
	}

	/** * ���ֽ��� * * @param str * @return */
	public String convert(String str) {
		String result = null;
		int ascii = getChsAscii(str);
		if (ascii > 0 && ascii < 160) {
			result = String.valueOf((char) ascii);
		} else {
			for (int i = (pyvalue.length - 1); i >= 0; i--) {
				if (pyvalue[i] <= ascii) {
					result = pystr[i];
					break;
				}
			}
		}
		return result;
	}

	/** * ������� * * @param chs * @return */
	public String getSelling(String chs) {
		String key, value;
		buffer = new StringBuilder();
		for (int i = 0; i < chs.length(); i++) {
			key = chs.substring(i, i + 1);
			if (key.getBytes().length >= 2) {
				value = convert(key);
				if (value == null) {
					value = "unknown";
				}
			} else {
				value = key;
			}
			buffer.append(value);
		}
		return buffer.toString();
	}

	public String getSpelling() {
		return this.getSelling(this.getResource());
	}

}

package com.pcjz.lems.business.common.view.personlist;

import com.pcjz.lems.business.entity.PersonInfoEntity;

import java.util.Comparator;

/**
 * 
 * @author xiaanming
 *
 */
public class PinyinComparator implements Comparator<PersonInfoEntity> {

	public int compare(PersonInfoEntity o1, PersonInfoEntity o2) {
		if (o1.getSortLetters().equals("@")
				|| o2.getSortLetters().equals("#")) {
			return -1;
		} else if (o1.getSortLetters().equals("#")
				|| o2.getSortLetters().equals("@")) {
			return 1;
		} else {
			return o1.getSortLetters().compareTo(o2.getSortLetters());
		}
	}

}

package com.pcjz.lems.business.widget.contractlist;

import android.os.Handler;
import android.support.v4.util.ArrayMap;
import android.text.TextUtils;

import com.github.promeg.pinyinhelper.Pinyin;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by you on 2017/9/8.
 */

public final class CNPinyinFactory {

    static final ArrayMap<Character, String> SURNAMES = new ArrayMap<>();

    static {
        SURNAMES.put('仇', "QIU");
        SURNAMES.put('柏', "BO");
        SURNAMES.put('牟', "MU");
        SURNAMES.put('颉', "XIE");
        SURNAMES.put('解', "XIE");
        SURNAMES.put('尉', "YU");
        SURNAMES.put('奇', "JI");
        SURNAMES.put('单', "SHAN");
        SURNAMES.put('谌', "SHEN");
        SURNAMES.put('乐', "YUE");
        SURNAMES.put('召', "SHAO");
        SURNAMES.put('朴', "PIAO");
        SURNAMES.put('区', "OU");
        SURNAMES.put('查', "ZHA");
        SURNAMES.put('曾', "ZENG");
        SURNAMES.put('缪', "MIAO");
    }

    static final char DEF_CHAR = '#';

    /**
     * 转换拼音, 考虑在子线程中运行
     * @param tList
     * @param <T>
     * @return
     */
    public static <T extends CN> void createCNPinyinList(List<T> tList, int requestCode, Handler handler) {
        if (tList != null && !tList.isEmpty()) {
            ArrayList<CNPinyin<T>> cnPinyinArrayList = new ArrayList<>(tList.size());
            for (T t : tList) {
                CNPinyin<T> pinyin = createCNPinyin(t);
                if (pinyin != null) {
                    cnPinyinArrayList.add(pinyin);
                }
            }
            handler.obtainMessage(requestCode, cnPinyinArrayList).sendToTarget();
        } else {
            handler.obtainMessage(requestCode, null).sendToTarget();
        }
    }

    public static <T extends CN> CNPinyin<T> createCNPinyin(T t) {
        if (t == null || (t.chineseText() == null && t.chineseContent() == null)) return null;
        String chinese = "";
        if (t.chineseText() != null) {
            chinese = t.chineseText().trim();
        }
        String chinese1 = "";
        if (t.chineseContent() != null) {
            chinese1 = t.chineseContent().trim();
        }
        if (TextUtils.isEmpty(chinese) && TextUtils.isEmpty(chinese1)) return null;
        CNPinyin cnPinyin = new CNPinyin(t);
        if (!TextUtils.isEmpty(chinese)) {
            char[] chars = chinese.toCharArray();
            String[] charPinyins = new String[chars.length];
            StringBuilder stringBuilder = new StringBuilder();
            int pinyinsTotalLength = 0;
            for (int i = 0; i < chars.length; i++) {
                char c = chars[i];
                //将输入的字符串转换为拼音,并区分多音字
                String pinyin = charToPinyin(chars[i], i);
                charPinyins[i] = pinyin;
                if (pinyin.length() > 0) {
                    stringBuilder.append(pinyin.charAt(0));
                } else {
                    stringBuilder.append(c);
                }
                pinyinsTotalLength += pinyin.length();
            }
            cnPinyin.pinyinsText = charPinyins;
            cnPinyin.firstCharText = getFirstChar(charPinyins);
            cnPinyin.firstCharsText = stringBuilder.toString();
            cnPinyin.pinyinsTextTotalLength = pinyinsTotalLength;
        }
        if (!TextUtils.isEmpty(chinese1)) {
            char[] chars = chinese1.toCharArray();
            String[] charPinyins = new String[chars.length];
            StringBuilder stringBuilder = new StringBuilder();
            int pinyinsTotalLength = 0;
            for (int i = 0; i < chars.length; i++) {
                char c = chars[i];
                //将输入的字符串转换为拼音,并区分多音字
                String pinyin = charToPinyin(chars[i], i);
                charPinyins[i] = pinyin;
                if (pinyin.length() > 0) {
                    stringBuilder.append(pinyin.charAt(0));
                } else {
                    stringBuilder.append(c);
                }
                pinyinsTotalLength += pinyin.length();
            }
            cnPinyin.pinyinsContent = charPinyins;
            cnPinyin.firstCharContent = getFirstChar(charPinyins);
            cnPinyin.firstCharsContent = stringBuilder.toString();
            cnPinyin.pinyinsContentTotalLength = pinyinsTotalLength;
        }
        return cnPinyin;
    }

    /**
     *
     * @param c
     * @param index
     * @return
     */
    private static String charToPinyin(char c, int index) {
        if (index == 0) {
            String pinyin = SURNAMES.get(c);
            if (pinyin != null) {
                return pinyin;
            }
        }
        String pinyin =  Pinyin.toPinyin(c);
        if (pinyin == null) {
            pinyin = String.valueOf(c);
        }
        return pinyin;
    }

    /**
     * 拼音首个字母
     * @param pinyins
     * @return
     */
    private static char getFirstChar(String[] pinyins) {
        if (pinyins != null && pinyins.length > 0) {
            String firstPinying = pinyins[0];
            if (firstPinying.length() > 0) {
                return charToUpperCase(firstPinying.charAt(0));
            }
        }
        return DEF_CHAR;
    }

    /**
     * 字符转大写
     * @param c
     * @return
     */
    private static char charToUpperCase(char c) {
        if (c >= 'a' && c <= 'z') {
            c -= 32;
        }
        return c;
    }

}

package com.pcjz.lems.business.widget.contractlist;

import android.os.Handler;
import android.text.TextUtils;

import com.pcjz.lems.business.common.utils.StringUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Created by you on 2017/9/8.
 */

public final class CNPinyinIndexFactory {
    /**
     * 转换搜索拼音集合, 考虑在子线程中运行
     *
     * @param cnPinyinList
     * @param keyword
     * @return
     */
    public static <T extends CN> void indexList(List<CNPinyin<T>> cnPinyinList, String keyword, int requestCode, Handler handler) {
        ArrayList<CNPinyinIndex<T>> cnPinyinIndexArrayList = new ArrayList<>();
        if (cnPinyinList != null && cnPinyinList.size() != 0) {
            for (CNPinyin<T> cnPinyin : cnPinyinList) {
                CNPinyinIndex<T> index = index(cnPinyin, keyword);
                if (index != null) {
                    cnPinyinIndexArrayList.add(index);
                }
            }
        }
        handler.obtainMessage(requestCode, cnPinyinIndexArrayList).sendToTarget();
    }

    /**
     * 匹配拼音
     *
     * @param cnPinyin
     * @return null代表没有匹配
     */
    public static <T extends CN> CNPinyinIndex<T> index(CNPinyin<T> cnPinyin, String keyword) {
        if (TextUtils.isEmpty(keyword)) return null;
        //匹配中文搜索
        CNPinyinIndex cnPinyinIndex = matcherChinese(cnPinyin, keyword);
        if (isContainChinese(keyword)) {//包含中文只匹配原字符
            return cnPinyinIndex;
        }
        if (cnPinyinIndex == null) {
            //匹配首字母搜索
            cnPinyinIndex = matcherFirst(cnPinyin, keyword);
            if (cnPinyinIndex == null) {
                //匹配全拼音搜索
                cnPinyinIndex = matchersPinyins(cnPinyin, keyword);
            }
        }
        return cnPinyinIndex;
    }

    /**
     * 匹配中文
     *
     * @param cnPinyin
     * @param keyword
     * @return
     */
    static CNPinyinIndex matcherChinese(CNPinyin cnPinyin, String keyword) {
        if (cnPinyin.data.chineseText() != null) {
            if (keyword.length() <= cnPinyin.data.chineseText().length()) {
                Matcher matcher = Pattern.compile(keyword, Pattern.CASE_INSENSITIVE).matcher(cnPinyin.data.chineseText());
                if (matcher.find()) {
                    if (cnPinyin.data.chineseContent() != null) {
                        if (keyword.length() <= cnPinyin.data.chineseContent().length()) {
                            Matcher matcher1 = Pattern.compile(keyword, Pattern.CASE_INSENSITIVE).matcher(cnPinyin.data.chineseContent());
                            if (matcher1.find()) {
                                return new CNPinyinIndex(cnPinyin, matcher.start(), matcher.end(), matcher1.start(), matcher1.end());
                            }
                        }
                    }
                    return new CNPinyinIndex(cnPinyin, matcher.start(), matcher.end(), 0, 0);
                }
            }
        }
        if (cnPinyin.data.chineseContent() != null) {
            if (keyword.length() <= cnPinyin.data.chineseContent().length()) {
                Matcher matcher1 = Pattern.compile(keyword, Pattern.CASE_INSENSITIVE).matcher(cnPinyin.data.chineseContent());
                if (matcher1.find()) {
                    return new CNPinyinIndex(cnPinyin, 0, 0, matcher1.start(), matcher1.end());
                }
            }
        }
        return null;
    }


    /**
     * 匹配首字母
     *
     * @param cnPinyin
     * @param keyword
     * @return
     */
    static CNPinyinIndex matcherFirst(CNPinyin cnPinyin, String keyword) {
        if (cnPinyin.pinyinsText != null) {
            if (keyword.length() <= cnPinyin.pinyinsText.length) {
                Matcher matcher = Pattern.compile(keyword, Pattern.CASE_INSENSITIVE).matcher(cnPinyin.firstCharsText);
                if (matcher.find()) {
                    if (cnPinyin.pinyinsContent != null) {
                        if (keyword.length() <= cnPinyin.pinyinsContent.length) {
                            Matcher matcher1 = Pattern.compile(keyword, Pattern.CASE_INSENSITIVE).matcher(cnPinyin.firstCharsContent);
                            if (matcher1.find()) {
                                return new CNPinyinIndex(cnPinyin, matcher.start(), matcher.end(), matcher1.start(), matcher1.end());
                            }
                        }
                    }
                    return new CNPinyinIndex(cnPinyin, matcher.start(), matcher.end(), 0, 0);
                }
            }
        }
        if (cnPinyin.pinyinsContent != null) {
            if (keyword.length() <= cnPinyin.pinyinsContent.length) {
                Matcher matcher1 = Pattern.compile(keyword, Pattern.CASE_INSENSITIVE).matcher(cnPinyin.firstCharsContent);
                if (matcher1.find()) {
                    return new CNPinyinIndex(cnPinyin, 0, 0, matcher1.start(), matcher1.end());
                }
            }
        }
        return null;
    }

    /**
     * 所有拼音匹配
     * @param cnPinyin
     * @param keyword
     * @return
     */
    static CNPinyinIndex matchersPinyins(CNPinyin cnPinyin, String keyword) {
        if (keyword.length() <= cnPinyin.pinyinsTextTotalLength) {
            String startAndEnd = startAndEnd(cnPinyin.pinyinsText, keyword);
            String[] split = startAndEnd.split("\\.");
            int start = Integer.parseInt(split[0]);
            int end = Integer.parseInt(split[1]);
            if (start >= 0 && end >= start) {
                if (keyword.length() <= cnPinyin.pinyinsContentTotalLength) {
                    String start1AndEnd1 = startAndEnd(cnPinyin.pinyinsContent, keyword);
                    String[] split1 = start1AndEnd1.split("\\.");
                    int start1 = Integer.parseInt(split1[0]);
                    int end1 = Integer.parseInt(split1[1]);
                    if (start1 >= 0 && end1 >= start1) {
                        return new CNPinyinIndex(cnPinyin, start, end, start1, end1);
                    }
                }
                return new CNPinyinIndex(cnPinyin, start, end, 0, 0);
            }
        }
        if (keyword.length() <= cnPinyin.pinyinsContentTotalLength) {
            String start1AndEnd1 = startAndEnd(cnPinyin.pinyinsContent, keyword);
            String[] split1 = start1AndEnd1.split("\\.");
            int start1 = Integer.parseInt(split1[0]);
            int end1 = Integer.parseInt(split1[1]);
            if (start1 >= 0 && end1 >= start1) {
                return new CNPinyinIndex(cnPinyin, 0, 0, start1, end1);
            }
        }
        return null;
    }

    private static String startAndEnd(String[] pinyins, String keyword) {
        int start = -1;
        int end = -1;
        for (int i = 0; i < pinyins.length; i++) {
            String pat = pinyins[i];
            if (pat.length() >= keyword.length()) {//首个位置索引
                Matcher matcher = Pattern.compile(keyword, Pattern.CASE_INSENSITIVE).matcher(pat);
                if (matcher.find() && matcher.start() == 0) {
                    start = i;
                    end = i + 1;
                    break;
                }
            } else {
                Matcher matcher = Pattern.compile(pat, Pattern.CASE_INSENSITIVE).matcher(keyword);
                if (matcher.find() && matcher.start() == 0) {//全拼匹配第一个必须在0位置
                    start = i;
                    String left = matcher.replaceFirst("");
                    end = end(pinyins, left, ++i);
                    break;
                }
            }
        }
        return start + "." + end;
    }

    /**
     * 根据匹配字符递归查找下一结束位置
     *
     * @param pinyinGroup
     * @param pattern
     * @param index
     * @return -1 匹配失败
     */
    private static int end(String[] pinyinGroup, String pattern, int index) {
        if (index < pinyinGroup.length) {
            String pinyin = pinyinGroup[index];
            if (pinyin.length() >= pattern.length()) {//首个位置索引
                Matcher matcher = Pattern.compile(pattern, Pattern.CASE_INSENSITIVE).matcher(pinyin);
                if (matcher.find() && matcher.start() == 0) {
                    return index + 1;
                }
            } else {
                Matcher matcher = Pattern.compile(pinyin, Pattern.CASE_INSENSITIVE).matcher(pattern);
                if (matcher.find() && matcher.start() == 0) {//全拼匹配第一个必须在0位置
                    String left = matcher.replaceFirst("");
                    return end(pinyinGroup, left, index + 1);
                }
            }
        }
        return -1;
    }

    private static boolean isContainChinese(String str) {
        Pattern p = Pattern.compile("[\u4e00-\u9fa5]");
        Matcher m = p.matcher(str);
        return m.find();
    }

}

实体类:联系人、拼音实体类(拼音,首字母,长度)、拼音下标类
package com.pcjz.lems.business.widget.contractlist;

import java.io.Serializable;

/**
 * Created by you on 2017/9/11.
 */

public interface CN extends Serializable {

    String chineseText();
    String chineseContent();
}

package com.pcjz.lems.business.entity;

import com.pcjz.lems.business.widget.contractlist.CN;

import java.io.Serializable;

/**
 * created by yezhengyu on 2017/9/19 15:49
 */

public class PersonInfoEntity implements CN,Serializable{
    private String empName;
    private String jobName;
    private String facephoto;
    private String backGroundColor;
    private String personId;
    private String projectPersonId;
    private String deleteStatus;
    private String sortLetters;  //显示数据拼音的首字母

    public String getEmpName() {
        return empName;
    }

    public void setEmpName(String empName) {
        this.empName = empName;
    }

    public String getJobName() {
        return jobName;
    }

    public void setJobName(String jobName) {
        this.jobName = jobName;
    }

    public String getFacephoto() {
        return facephoto;
    }

    public void setFacephoto(String facephoto) {
        this.facephoto = facephoto;
    }

    public String getPersonId() {
        return personId;
    }

    public void setPersonId(String personId) {
        this.personId = personId;
    }

    public String getProjectPersonId() {
        return projectPersonId;
    }

    public void setProjectPersonId(String projectPersonId) {
        this.projectPersonId = projectPersonId;
    }

    public String getSortLetters() {
        return sortLetters;
    }

    public void setSortLetters(String sortLetters) {
        this.sortLetters = sortLetters;
    }

    public String getBackGroundColor() {
        return backGroundColor;
    }

    public void setBackGroundColor(String backGroundColor) {
        this.backGroundColor = backGroundColor;
    }

    public String getDeleteStatus() {
        return deleteStatus;
    }

    public void setDeleteStatus(String deleteStatus) {
        this.deleteStatus = deleteStatus;
    }

    @Override
    public String chineseText() {
        return empName;
    }

    @Override
    public String chineseContent() {
        return jobName;
    }
}

package com.pcjz.lems.business.widget.contractlist;

import java.io.Serializable;

import static com.pcjz.lems.business.widget.contractlist.CNPinyinFactory.DEF_CHAR;
/**
 * Created by you on 2017/9/7.
 */

public class CNPinyin <T extends CN> implements Serializable, Comparable<CNPinyin<T>> {

    /**
     * 对应首字首拼音字母
     */
    char firstCharText;
    /**
     * 所有字符中的拼音首字母
     */
    String firstCharsText;
    /**
     * 对应的所有字母拼音
     */
    String[] pinyinsText;

    /**
     * 拼音总长度
     */
    int pinyinsTextTotalLength;


    //此处是加了内容后对内容的处理
    char firstCharContent;
    String firstCharsContent;
    String[] pinyinsContent;
    int pinyinsContentTotalLength;


    public final T data;

    CNPinyin(T data) {
        this.data = data;
    }

    public char getFirstCharText() {
        return firstCharText;
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder().append("--firstChar--").append(firstCharText).append("--pinyins:");
        for (String str : pinyinsText) {
            sb.append(str);
        }
        return sb.toString();
    }

    int compareValue() {
        if (firstCharText == DEF_CHAR) {
            return 'Z' + 1;
        }
        return firstCharText;
    }

    @Override
    public int compareTo(CNPinyin<T> tcnPinyin) {
        int compare = compareValue() - tcnPinyin.compareValue();
        if (compare == 0) {
            String chinese1 = data.chineseText();
            String chinese2 = tcnPinyin.data.chineseText();
            return chinese1.compareTo(chinese2);
        }
        return compare;
    }
}

package com.pcjz.lems.business.widget.contractlist;

import java.io.Serializable;

/**
 * Created by you on 2017/9/8.
 */

public class CNPinyinIndex <T extends CN> implements Serializable {

    public final CNPinyin<T> cnPinyin;

    //对名字进行变色处理
    public final int startText;
    public final int endText;

    //此处是加了内容后对内容的处理
    public final int startContent;
    public final int endContent;

    CNPinyinIndex(CNPinyin cnPinyin, int startText, int endText, int startContent, int endContent) {
        this.cnPinyin = cnPinyin;
        this.startText = startText;
        this.endText = endText;
        this.startContent = startContent;
        this.endContent = endContent;
    }

    @Override
    public String toString() {
        return cnPinyin.toString()+"  start " + startText+"  end " + endText;
    }
}

  • 4
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 9
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值