仿Android联系人SideBar排序,依据拼音A-Z字母快速查找,以及输入搜索条件过滤,显示姓名的文字图片

仿Android联系人SideBar排序,根据拼音A-Z字母快速查找,以及输入搜索条件过滤,显示姓名的文字图片

关注finddreams,一起分享,一起进步!http://blog.****.net/finddreams/article/details/44623235

话不多说,直接上干货,图片如下:
仿Android联系人SideBar排序,依据拼音A-Z字母快速查找,以及输入搜索条件过滤,显示姓名的文字图片

仿Android联系人SideBar排序,根据拼音A-Z字母快速查找,以及输入搜索条件过滤,显示姓名的文字图片。
这样的效果相信大家并不陌生,我们在APP中都司空见惯了,比如在选择地址的时候,选择国家,省份等等。这样的效果很多大神也都写过相应的博客,大体上实现的方式都差不多,今天我也给大家模仿一下Android联系人的排序实现。
1.首先我们把这几个工具类拷贝到自己的项目中,这些都是很常见的类:
CharacterParser –这是用来把中文转成拼音的工具类
PinyinComparator –拼音首字母的比较器
SideBar –右侧的竖条,显示的是二十六个字母以及*,和#号
SortModel –放排序name和key的bean

2.加上一个ClearEditText来实现带删除当前输入内容按钮EditText
在ClearEditText中输入内容,然后监听它的TextChangedListener来实现搜索条件的过滤,具体代码见最下面的源码:

3.接下来我们来看看实现这个效果改如何布局,看一下我们的layout布局文件:

<?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:focusableInTouchMode="true">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical" >

        <com.finddreams.sortedcontact.ClearEditText
            android:id="@+id/filter_edit"
            android:layout_width="fill_parent"
            android:layout_height="40dp"
            android:layout_marginLeft="5dp"
            android:layout_marginRight="5dp"
            android:layout_marginTop="5dip"
            android:gravity="center"
            android:background="@drawable/acm_inputbox"
            android:drawableLeft="@drawable/search"
            android:hint="@string/search"
            android:singleLine="true"
            android:textSize="15.0dip" />

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

            <ListView
                android:id="@+id/sortlist"
                android:layout_width="fill_parent"
                android:layout_height="fill_parent"
                   android:background="@color/whites"
                  android:listSelector="@drawable/comm_btn_selector"
                android:layout_gravity="center" />

            <TextView
                android:id="@+id/dialog"
                android:layout_width="80.0dip"
                android:layout_height="80.0dip"
                android:layout_gravity="center"
                android:background="@drawable/number_base"
                android:gravity="center"
                android:textColor="#ffffffff"
                android:textSize="30.0dip"
                android:visibility="invisible" />

            <com.finddreams.sortedcontact.sortlist.SideBar
                android:id="@+id/sidrbar"
                android:layout_width="30.0dip"
                android:layout_height="fill_parent"
                android:layout_gravity="right|center" />
        </FrameLayout>
    </LinearLayout>


</RelativeLayout>

4.然后我们就可以在Activity代码中调用了,具体的代码如下:

/**
 * @Description:联系人显示界面
 * @author http://blog.****.net/finddreams
 */
public class MainActivity extends Activity {

    private View mBaseView;
    private ListView sortListView;
    private SideBar sideBar;
    private TextView dialog;
    private SortAdapter adapter;
    private ClearEditText mClearEditText;
    private Map<String, String> callRecords;

    private CharacterParser characterParser;
    private List<SortModel> SourceDateList;

    private PinyinComparator pinyinComparator;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main_contact);
        initView();
        initData();
    }

    private void initView() {
        sideBar = (SideBar) this.findViewById(R.id.sidrbar);
        dialog = (TextView) this.findViewById(R.id.dialog);

        sortListView = (ListView) this.findViewById(R.id.sortlist);

    }

    private void initData() {
        // 实例化汉字转拼音类
        characterParser = CharacterParser.getInstance();

        pinyinComparator = new PinyinComparator();

        sideBar.setTextView(dialog);

        // 设置右侧触摸监听
        sideBar.setOnTouchingLetterChangedListener(new OnTouchingLetterChangedListener() {

            @SuppressLint("NewApi")
            @Override
            public void onTouchingLetterChanged(String s) {
                // 该字母首次出现的位置
                int position = adapter.getPositionForSection(s.charAt(0));
                if (position != -1) {
                    sortListView.setSelection(position);
                }
            }
        });

        sortListView.setOnItemClickListener(new OnItemClickListener() {

            @Override
            public void onItemClick(AdapterView<?> parent, View view,
                    int position, long id) {
                // 这里要利用adapter.getItem(position)来获取当前position所对应的对象
                // Toast.makeText(getApplication(),
                // ((SortModel)adapter.getItem(position)).getName(),
                // Toast.LENGTH_SHORT).show();
                String number = callRecords.get(((SortModel) adapter
                        .getItem(position)).getName());
                Toast.makeText(MainActivity.this, number, 0).show();
            }
        });

        new ConstactAsyncTask().execute(0);

    }

    private class ConstactAsyncTask extends
            AsyncTask<Integer, Integer, Integer> {

        @Override
        protected Integer doInBackground(Integer... arg0) {
            int result = -1;
            callRecords = ConstactUtil.getAllCallRecords(MainActivity.this);
            result = 1;
            return result;
        }

        @Override
        protected void onPostExecute(Integer result) {
            super.onPostExecute(result);
            if (result == 1) {
                List<String> constact = new ArrayList<String>();
                for (Iterator<String> keys = callRecords.keySet().iterator(); keys
                        .hasNext();) {
                    String key = keys.next();
                    constact.add(key);
                }
                String[] names = new String[] {};
                names = constact.toArray(names);
                SourceDateList = filledData(names);

                // 根据a-z进行排序源数据
                Collections.sort(SourceDateList, pinyinComparator);
                adapter = new SortAdapter(MainActivity.this, SourceDateList);
                sortListView.setAdapter(adapter);

                mClearEditText = (ClearEditText) MainActivity.this
                        .findViewById(R.id.filter_edit);
                mClearEditText
                        .setOnFocusChangeListener(new OnFocusChangeListener() {

                            @Override
                            public void onFocusChange(View arg0, boolean arg1) {
                                mClearEditText.setGravity(Gravity.LEFT
                                        | Gravity.CENTER_VERTICAL);

                            }
                        });
                // 根据输入框输入值的改变来过滤搜索
                mClearEditText.addTextChangedListener(new TextWatcher() {

                    @Override
                    public void onTextChanged(CharSequence s, int start,
                            int before, int count) {
                        // 当输入框里面的值为空,更新为原来的列表,否则为过滤数据列表
                        filterData(s.toString());
                    }

                    @Override
                    public void beforeTextChanged(CharSequence s, int start,
                            int count, int after) {

                    }

                    @Override
                    public void afterTextChanged(Editable s) {
                    }
                });
            }
        }

        @Override
        protected void onPreExecute() {
            super.onPreExecute();
        }

    }

    /**
     * 为ListView填充数据
     * 
     * @param date
     * @return
     */
    private List<SortModel> filledData(String[] date) {
        List<SortModel> mSortList = new ArrayList<SortModel>();

        for (int i = 0; i < date.length; i++) {
            SortModel sortModel = new SortModel();
            sortModel.setName(date[i]);
            // 汉字转换成拼音
            String pinyin = characterParser.getSelling(date[i]);
            String sortString = pinyin.substring(0, 1).toUpperCase();

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

            mSortList.add(sortModel);
        }
        return mSortList;

    }

    /**
     * 根据输入框中的值来过滤数据并更新ListView
     * 
     * @param filterStr
     */
    private void filterData(String filterStr) {
        List<SortModel> filterDateList = new ArrayList<SortModel>();

        if (TextUtils.isEmpty(filterStr)) {
            filterDateList = SourceDateList;
        } else {
            filterDateList.clear();
            for (SortModel sortModel : SourceDateList) {
                String name = sortModel.getName();
                if (name.indexOf(filterStr.toString()) != -1
                        || characterParser.getSelling(name).startsWith(
                                filterStr.toString())) {
                    filterDateList.add(sortModel);
                }
            }
        }

        // 根据a-z进行排序
        Collections.sort(filterDateList, pinyinComparator);
        adapter.updateListView(filterDateList);
    }

}

5.为了获取到联系人的数据,我们首先当然是不要忘了添加获取联系人的权限了,其次这里有一个获取联系人的工具类,十分的方便:

public class ConstactUtil {
    /**
     * 获取所有数据
     * 
     * @return
     */
    public static Map<String, String> getAllCallRecords(Context context) {
        Map<String, String> temp = new HashMap<String, String>();
        Cursor c = context.getContentResolver().query(
                ContactsContract.Contacts.CONTENT_URI,
                null,
                null,
                null,
                ContactsContract.Contacts.DISPLAY_NAME
                        + " COLLATE LOCALIZED ASC");
        if (c.moveToFirst()) {
            do {
                // 获得联系人的ID号
                String contactId = c.getString(c
                        .getColumnIndex(ContactsContract.Contacts._ID));
                // 获得联系人姓名
                String name = c
                        .getString(c
                                .getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
                // 查看该联系人有多少个电话号码。如果没有这返回值为0
                int phoneCount = c
                        .getInt(c
                                .getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER));
                String number = null;
                if (phoneCount > 0) {
                    // 获得联系人的电话号码
                    Cursor phones = context.getContentResolver().query(
                            ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
                            null,
                            ContactsContract.CommonDataKinds.Phone.CONTACT_ID
                                    + " = " + contactId, null, null);
                    if (phones.moveToFirst()) {
                        number = phones
                                .getString(phones
                                        .getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
                    }
                    phones.close();
                }
                temp.put(name, number);
            } while (c.moveToNext());
        }
        c.close();
        return temp;
    }
}

6.我们来看看SortAdapter 是如何写的

/**
 * @Description:用来处理集合中数据的显示与排序
 * @author http://blog.****.net/finddreams
 */
public class SortAdapter extends BaseAdapter implements SectionIndexer {
    private List<SortModel> list = null;
    private Context mContext;

    public SortAdapter(Context mContext, List<SortModel> list) {
        this.mContext = mContext;
        this.list = list;
    }

    /**
     * 当ListView数据发生变化时,调用此方法来更新ListView
     * 
     * @param list
     */
    public void updateListView(List<SortModel> list) {
        this.list = list;
        notifyDataSetChanged();
    }

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

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

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

    public View getView(final int position, View view, ViewGroup arg2) {
        ViewHolder viewHolder = null;
        final SortModel mContent = list.get(position);
        if (view == null) {
            viewHolder = new ViewHolder();
            view = LayoutInflater.from(mContext).inflate(
                    R.layout.phone_constacts_item, null);
            viewHolder.tvTitle = (TextView) view.findViewById(R.id.title);
            viewHolder.tvLetter = (TextView) view.findViewById(R.id.catalog);
            viewHolder.icon = (ImageTextView) view.findViewById(R.id.icon);
            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.tvLetter.setText(mContent.getSortLetters());
        } else {
            viewHolder.tvLetter.setVisibility(View.GONE);
        }

        viewHolder.tvTitle.setText(this.list.get(position).getName());
        viewHolder.icon.setText(this.list.get(position).getName());
        viewHolder.icon
                .setIconText(mContext, this.list.get(position).getName());
        return view;

    }

    final static class ViewHolder {
        TextView tvLetter;
        TextView tvTitle;
        ImageTextView icon;

    }

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

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

        return -1;
    }

    /**
     * 提取英文的首字母,非英文字母用#代替。
     * 
     * @param str
     * @return
     */
    private String getAlpha(String str) {
        String sortStr = str.trim().substring(0, 1).toUpperCase();
        // 正则表达式,判断首字母是否是英文字母
        if (sortStr.matches("[A-Z]")) {
            return sortStr;
        } else {
            return "#";
        }
    }

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

7.为了实现每个名字前面带有这个名字中第一个字的图片,我们首先要引入一个自定义的ImageTextView类,它是继承自TextView的,我们所做的只是在拿到这个TextView的Text内容,然后根据这个内容画出一张图片,具体代码如下:
/**
* @Description: 文字图片,这个相信大家都知道,比如QQ底部导航上的未读消息数
* @author http://blog.****.net/finddreams
*/
public class ImageTextView extends TextView {
private Bitmap bitmap;
private String text;
Drawable d;

public ImageTextView(Context context) {
    super(context);
}

public ImageTextView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
}

public ImageTextView(Context context, AttributeSet attrs) {
    super(context, attrs);
}

public void setIconText(Context context, String text) {
    text = this.getText().toString().substring(0, 1);
    bitmap = BitmapUtil.getIndustry(context, text);
    d = BitmapUtil.bitmapTodrawable(bitmap);
    this.setCompoundDrawables(d, null, null, null);
}

}
其中BitmapUtil有两个方法:

/**
     * 根据文字获取图片
    * @param text
     * @return
     */
    public static Bitmap getIndustry(Context context, String text) {
        String color = "#ffeeeade";

        Bitmap src = BitmapFactory.decodeResource(context.getResources(),
                R.drawable.ic_launcher);
        int x = src.getWidth();
        int y = src.getHeight();
        Bitmap bmp = Bitmap.createBitmap(x, y, Bitmap.Config.ARGB_8888);
        Canvas canvasTemp = new Canvas(bmp);
        canvasTemp.drawColor(Color.parseColor(color));
        Paint p = new Paint(Paint.FAKE_BOLD_TEXT_FLAG | Paint.ANTI_ALIAS_FLAG);
        p.setColor(Color.parseColor("#ff4e0a13"));
        p.setAlpha(45);
        p.setFilterBitmap(true);
        int size = (int) (18 * context.getResources().getDisplayMetrics().density);
        p.setTextSize(size);
        float tX = (x - getFontlength(p, text)) / 2;
        float tY = (y - getFontHeight(p)) / 2 + getFontLeading(p);
        canvasTemp.drawText(text, tX, tY, p);
        return toRoundCorner(bmp, 2);
    }
/**
     * @param bitmap
     * @return
     */
    public static Drawable bitmapTodrawable(Bitmap bitmap) {
        Drawable drawable = new BitmapDrawable(bitmap);
        drawable.setBounds(0, 0, bitmap.getWidth(), bitmap.getHeight());
        return drawable;
    }

这样就可以实现文字图片的效果了,是不是非常的简单。

最后需要的朋友可以去这里下载源码,学习学习:
https://github.com/finddreams/SortedContactUI