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

话不多说,直接上干货,图片如下:

仿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.csdn.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.csdn.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.csdn.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

更多相关文章

  1. 一句话锁定MySQL数据占用元凶
  2. 金三银四背后,一个 Android(安卓)程序员的面试心得
  3. MVVM框架的使用介绍和为什么选择用MVVM框架
  4. 如何将旧手机数据转移至iPhone7?旧Android数据转移到新iPhone全攻
  5. Android入门笔记 - 数据存储 - 网络
  6. Android(安卓)本地文件缓存各个方法获取的路径小结
  7. Android(安卓)Paging分页库的学习(一)—— 结合本地数据进行分页加
  8. Android近期任务列表Recent List(Recents Screen)的实现方式
  9. 在Android系统使用socket在Java层和native之间数据通信

随机推荐

  1. Android: 系统默认音量
  2. How to Create QuickAction Dialog in An
  3. Android(安卓)onTouch事件
  4. android sdk更新失败解决办法
  5. Android(安卓)7.1 触摸事件代码跟踪
  6. android 开发积累
  7. Android(安卓)屏幕滑动事件
  8. android 软件源码
  9. android IOS webview word document
  10. android中使用HTTP协议和TCP协议实现上传