• 本文给出了Android读取通讯录联系人的一般方法,且在读取Android通讯录联系人时候,将结果有序化(按照联系人姓名的首字符依次顺序读取:A ~ Z)。 读取的结果如图所示: 现给出实现该种Android通讯录读取的...

    本文给出了Android读取通讯录联系人的一般方法,且在读取Android通讯录联系人时候,将结果有序化(按照联系人姓名的首字符依次顺序读取:A ~ Z)。

    读取的结果如图所示:


    现给出实现该种Android通讯录读取的代码:

    package zhangphil.contacts;
    
    import java.util.ArrayList;
    
    import android.app.ListActivity;
    import android.content.ContentResolver;
    import android.content.Context;
    import android.database.Cursor;
    import android.net.Uri;
    import android.os.Bundle;
    import android.provider.ContactsContract;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.ArrayAdapter;
    import android.widget.ListView;
    import android.widget.TextView;
    
    public class MainActivity extends ListActivity {
    
    	@Override
    	protected void onCreate(Bundle savedInstanceState) {
    		super.onCreate(savedInstanceState);
    
    		ArrayList<Contact> contacts = new ArrayList<Contact>();
    		readContacts(contacts);
    
    		ListView listView = this.getListView();
    		ArrayAdapter<Contact> adapter = new MyAdapter(this,
    				android.R.layout.simple_list_item_2, contacts);
    		listView.setAdapter(adapter);
    	}
    
    	private class MyAdapter extends ArrayAdapter<Contact> {
    
    		private int resource;
    		private LayoutInflater inflater = null;
    		private ArrayList<Contact> contacts;
    
    		public MyAdapter(Context context, int resource,
    				ArrayList<Contact> contacts) {
    			super(context, resource);
    			this.resource = resource;
    			this.contacts = contacts;
    
    			inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    		}
    
    		@Override
    		public View getView(int position, View convertView, ViewGroup parent) {
    
    			if (convertView == null)
    				convertView = inflater.inflate(resource, null);
    
    			Contact c = getItem(position);
    
    			TextView text1 = (TextView) convertView
    					.findViewById(android.R.id.text1);
    			TextView text2 = (TextView) convertView
    					.findViewById(android.R.id.text2);
    
    			//首字符,分组的依据。
    			text1.setText(c.firstLetterOfName());
    			
    			//详情。
    			text2.setText(c.name + " " + c.getPhoneNumbers());
    
    			return convertView;
    		}
    
    		@Override
    		public Contact getItem(int pos) {
    			return contacts.get(pos);
    		}
    
    		@Override
    		public int getCount() {
    			return contacts.size();
    		}
    	}
    
    	// 读取设备联系人的一般方法。大致流程就是这样,模板化的操作代码。
    	private void readContacts(ArrayList<Contact> contacts) {
    		Uri uri = Uri.parse("content://com.android.contacts/contacts");
    		ContentResolver reslover = this.getContentResolver();
    
    		// 在这里我们给query传递进去一个SORT_KEY_PRIMARY。
    		// 告诉ContentResolver获得的结果安装联系人名字的首字母有序排列。
    		Cursor cursor = reslover.query(uri, null, null, null,
    				android.provider.ContactsContract.Contacts.SORT_KEY_PRIMARY);
    
    		while (cursor.moveToNext()) {
    
    			// 联系人ID
    			String id = cursor
    					.getString(cursor
    							.getColumnIndex(android.provider.ContactsContract.Contacts._ID));
    
    			// Sort Key,读取的联系人按照姓名从 A->Z 排序分组。
    			String sort_key_primary = cursor
    					.getString(cursor
    							.getColumnIndex(android.provider.ContactsContract.Contacts.SORT_KEY_PRIMARY));
    
    			// 获得联系人姓名
    			String name = cursor
    					.getString(cursor
    							.getColumnIndex(android.provider.ContactsContract.Contacts.DISPLAY_NAME));
    
    			Contact mContact = new Contact();
    			mContact.id = id;
    			mContact.name = name;
    			mContact.sort_key_primary = sort_key_primary;
    
    			// 获得联系人手机号码
    			Cursor phone = reslover.query(
    					ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null,
    					ContactsContract.CommonDataKinds.Phone.CONTACT_ID + "="
    							+ id, null, null);
    
    			// 取得电话号码(可能存在多个号码)
    			// 因为同一个名字下,用户可能存有一个以上的号,
    			// 遍历。
    			ArrayList<String> phoneNumbers = new ArrayList<String>();
    			while (phone.moveToNext()) {
    				int phoneFieldColumnIndex = phone
    						.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER);
    				String phoneNumber = phone.getString(phoneFieldColumnIndex);
    				phoneNumbers.add(phoneNumber);
    			}
    
    			mContact.phoneNumbers = phoneNumbers;
    
    			contacts.add(mContact);
    		}
    	}
    
    	// 用于装载从联系人数据库中读取到的数据。
    	// 结构化数据,便于数据操作和访问。
    	private class Contact {
    		public String id;
    		public String name;
    		public String sort_key_primary;
    		public ArrayList<String> phoneNumbers;
    		
    		//获得一个联系人名字的首字符。
    		//比如一个人的名字叫“安卓”,那么这个人联系人的首字符是:A。
    		public	String	firstLetterOfName(){
    			String s=sort_key_primary.charAt(0)+"";
    			return	s.toUpperCase();
    		}
    
    		public String getPhoneNumbers() {
    			String phones = " ";
    			for (int i = 0; i < phoneNumbers.size(); i++) {
    				phones += "号码" + i + ":" + phoneNumbers.get(i);
    			}
    
    			return phones;
    		}
    	}
    }


    不要忘记在项目的AndroidManifest.xml文件中添加Android读写通讯录联系人的权限:

     <!-- 写权限 -->
        <uses-permission android:name="android.permission.WRITE_CONTACTS" />
        <!-- 读权限 -->
        <uses-permission android:name="android.permission.READ_CONTACTS" />


    
    展开全文
  • 需求 通过搜索联系人的姓名获取相应的详细人信息,也可通过右侧字母条搜索相应的联系人信息。 主要代码如下: MainActivity public class MainActivity extends AppCompatActivity { private ListView sortListView...

    需求
    通过搜索联系人的姓名获取相应的详细人信息,也可通过右侧字母条搜索相应的联系人信息。
    主要代码如下:
    MainActivity

    public class MainActivity extends AppCompatActivity {
        private ListView sortListView;
        private SideLetterUtil sideLetterUtil;
        private TextView dialog;
        private SortAdapter adapter;
        private ClearEditText mClearEditText;
        private String mobile,//被授权人电话号码
                name;//被授权人姓名
        /**
         * 查询通讯录名字
         */
        private Uri contactsUrl = ContactsContract.Contacts.CONTENT_URI;
        private ContentResolver resolver;
        private List<ContactsBean> nameList;
        /**
         * 汉字转换成拼音的类
         */
        private CharacterParser characterParser;
        private List<ContactsBean> SourceDateList;
    
        /**
         * 根据拼音来排列ListView里面的数据类
         */
        private ContactsPinyinComparator pinyinComparator;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            getPersimmionInfo();
        }
    
        private void getPersimmionInfo() {
            if (Build.VERSION.SDK_INT >= 23) {
                //1. 检测是否添加权限   PERMISSION_GRANTED  表示已经授权并可以使用
                if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) {
                    //手机为Android6.0的版本,权限未授权去i请授权
                    //2. 申请请求授权权限
                    //1. Activity
                    // 2. 申请的权限名称
                    // 3. 申请权限的 请求码
                    ActivityCompat.requestPermissions(this, new String[]
                            {Manifest.permission.READ_CONTACTS//通话录
                            }, 1005);
                } else {//手机为Android6.0的版本,权限已授权可以使用
                    // 执行下一步
                    initContacts();
                }
    
            } else {//手机为Android6.0以前的版本,可以使用
                initContacts();
            }
    
        }
    
        //  重写方法    当权限申请后     执行 接收结果的作用
        @Override
        public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
            super.onRequestPermissionsResult(requestCode, permissions, grantResults);
            // 先判断请求码 与 请求时的  是否一致
            if (requestCode == 1005) {
                //  判断请求结果长度     且  结果 为  允许访问  则 进行使用;第一次授权成功后
                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    // 可以使用
                    initContacts();
                } else {//未授权不可以使用
                    // 摄像机或读写内存卡权限授权将不能使用以下功能。
                    Toast.makeText(MainActivity.this, "未授权不可以使用", Toast.LENGTH_SHORT).show();
                }
            }
        }
    
        private void initContacts() {
            //实例化汉字转拼音类
            characterParser = CharacterParser.getInstance();
            pinyinComparator = new ContactsPinyinComparator();
            //右侧26个字母和#
            sideLetterUtil = (SideLetterUtil) findViewById(R.id.sidrbar);
            //中间显示字母
            dialog = (TextView) findViewById(R.id.dialog);
            sideLetterUtil.setTextView(dialog);
            //设置右侧触摸监听
            sideLetterUtil.setOnTouchingLetterChangedListener(new SideLetterUtil.OnTouchingLetterChangedListener() {
    
                @Override
                public void onTouchingLetterChanged(String s) {
                    //该字母首次出现的位置
                    int position = adapter.getPositionForSection(s.charAt(0));
                    if (position != -1) {
                        sortListView.setSelection(position);
                    }
    
                }
            });
    
            sortListView = (ListView) findViewById(R.id.lv_contacts_item);
            /**
             * 查询通讯录名字
             */
            nameList = new ArrayList<>();
            resolver = getContentResolver();
            //用于查询电话号码的URI
            Uri phoneUri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI;
            // 查询的字段
            String[] projection = {ContactsContract.CommonDataKinds.Phone._ID,//Id
                    ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME,//通讯录姓名
                    ContactsContract.CommonDataKinds.Phone.DATA1, "sort_key",//通讯录手机号
                    ContactsContract.CommonDataKinds.Phone.CONTACT_ID,//通讯录Id
                    ContactsContract.CommonDataKinds.Phone.PHOTO_ID,//手机号Id
                    ContactsContract.CommonDataKinds.Phone.LOOKUP_KEY};
            Cursor cursor = resolver.query(phoneUri, projection, null, null, null);
            while ((cursor.moveToNext())) {
                String name = cursor.getString(1);
                String phone = cursor.getString(2);
                nameList.add(new ContactsBean(name, phone));
            }
            SourceDateList = filledData(nameList);
            // 根据a-z进行排序源数据
            Collections.sort(SourceDateList, pinyinComparator);
            adapter = new SortAdapter(this, SourceDateList);
            sortListView.setAdapter(adapter);
            adapter.setOnCliker(new SortAdapter.OnClicker() {
                @Override
                public void onClik(String name1, String phone1) {
                    //这里要利用adapter.getItem(position)来获取当前position所对应的对象
                    mobile = phone1;
                    if (MobileUtil.isMobileNO(mobile)) {
                        //无通讯姓名则为StrConfig.CONTACTS_NAME_NULL
                        name = (TextUtils.equals(name1, "未备注联系人"))
                                ? "null" : name1;
                        Toast.makeText(MainActivity.this,
                                name + mobile, Toast.LENGTH_SHORT).show();
                    } else {
                        //该用户无手机号,或手机号格式不正确
                        Toast.makeText(MainActivity.this,
                                "该用户无手机号,或手机号格式不正确", Toast.LENGTH_SHORT).show();
                    }
                }
            });
            mClearEditText = findViewById(R.id.filter_edit);
            //根据输入框输入值的改变来过滤搜索
            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) {
                }
            });
        }
    
        /**
         * 为ListView填充数据
         */
        private List<ContactsBean> filledData(List<ContactsBean> date) {
            List<ContactsBean> mSortList = new ArrayList<ContactsBean>();
            for (int i = 0; i < date.size(); i++) {
                ContactsBean contactsBean = new ContactsBean();
                contactsBean.setName(date.get(i).getName());
                contactsBean.setPhone(date.get(i).getPhone());
                //汉字转换成拼音
                String pinyin = characterParser.getSelling(date.get(i).getName());
                String sortString = pinyin.substring(0, 1).toUpperCase();
    
                // 正则表达式,判断首字母是否是英文字母
                if (sortString.matches("[A-Z]")) {
                    contactsBean.setSortLetters(sortString.toUpperCase());
                } else {
                    contactsBean.setSortLetters("#");
                }
                mSortList.add(contactsBean);
            }
            return mSortList;
    
        }
    
        /**
         * 根据输入框中的值来过滤数据并更新ListView
         *
         * @param filterStr
         */
        private void filterData(String filterStr) {
            List<ContactsBean> filterDateList = new ArrayList<ContactsBean>();
    
            if (TextUtils.isEmpty(filterStr)) {
                filterDateList = SourceDateList;
            } else {
                filterDateList.clear();
                for (ContactsBean contactsBean : SourceDateList) {
                    String name = contactsBean.getName();
                    if (name.indexOf(filterStr.toString()) != -1 || characterParser.getSelling(name).startsWith(filterStr.toString())) {
                        filterDateList.add(contactsBean);
                    }
                }
            }
            // 根据a-z进行排序
            Collections.sort(filterDateList, pinyinComparator);
            adapter.updateListView(filterDateList);
        }
    }
    
    

    SortAdapter

    public class SortAdapter extends BaseAdapter implements SectionIndexer {
        private List<ContactsBean> list = null;
        private Context mContext;
        private OnClicker onClicker;
    
        public SortAdapter(Context mContext, List<ContactsBean> list) {
            this.mContext = mContext;
            this.list = list;
        }
    
        /**
         * 当ListView数据发生变化时,调用此方法来更新ListView
         *
         * @param list
         */
        public void updateListView(List<ContactsBean> 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 ContactsBean mContent = list.get(position);
            if (view == null) {
                viewHolder = new ViewHolder();
                view = LayoutInflater.from(mContext).inflate(R.layout.contacts_item, null);
                viewHolder.rlContacts = view.findViewById(R.id.rl_contacts);
                viewHolder.tvTitle = view.findViewById(R.id.tv_contacts_item_title);
                viewHolder.tvLetter = view.findViewById(R.id.tv_contacts_item_catalog);
                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);
            }
            final String mobile = this.list.get(position).getPhone()
                    .replaceAll(" ", "")
                    .replaceAll("\\+", "")
                    .replaceAll("-", "");
            viewHolder.tvTitle.setText(this.list.get(position).getName());
            viewHolder.rlContacts.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    onClicker.onClik(list.get(position).getName(), mobile);
                }
            });
            return view;
    
        }
    
    
        final static class ViewHolder {
            private TextView tvLetter,//首字母
                    tvTitle;//名字
            private RelativeLayout rlContacts;
            //tvIsImpower;//是否授权
        }
    
    
        /**
         * 根据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;
        }
    
        public void setOnCliker(OnClicker onClicker) {
            this.onClicker = onClicker;
        }
    
        /**
         * 提取英文的首字母,非英文字母用#代替。
         *
         * @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;
        }
    
        public interface OnClicker {
            void onClik(String name, String phone);
        }
    }
    

    SideLetterUtil

    public class SideLetterUtil extends View {
        // 触摸事件
        private OnTouchingLetterChangedListener onTouchingLetterChangedListener;
        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 TextView mTextDialog;
        private Context context;
    
        public void setTextView(TextView mTextDialog) {
            this.mTextDialog = mTextDialog;
            // this.mTextDialog.setTextColor(getResources().getColor(R.color.primary_green));
        }
    
        public SideLetterUtil(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
            this.context = context;
        }
    
        public SideLetterUtil(Context context, AttributeSet attrs) {
            super(context, attrs);
            this.context = context;
        }
    
        public SideLetterUtil(Context context) {
            super(context);
            this.context = context;
        }
    
        /**
         * 重写这个方法
         */
        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.rgb(33, 65, 98));
                paint.setColor(getResources().getColor(R.color.primary_green));
                paint.setTypeface(Typeface.DEFAULT_BOLD);
                paint.setAntiAlias(true);
    
                paint.setTextSize(DensityUtil.dp2px(context, 8));
                // 选中的状态
                if (i == choose) {
                    paint.setColor(Color.parseColor("#3399ff"));
                    paint.setFakeBoldText(true);
                }
                // x坐标等于中间-字符串宽度的一半.
                float xPos = width / 2 - paint.measureText(b[i]) / 2;
                float yPos = singleHeight * i + singleHeight;
                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;
        }
    
        /**
         * 向外公开的方法
         *
         * @param onTouchingLetterChangedListener
         */
        public void setOnTouchingLetterChangedListener(
                OnTouchingLetterChangedListener onTouchingLetterChangedListener) {
            this.onTouchingLetterChangedListener = onTouchingLetterChangedListener;
        }
    
        /**
         * 接口
         */
        public interface OnTouchingLetterChangedListener {
            public void onTouchingLetterChanged(String s);
        }
    
    }
    

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

    展开全文
  • 1.好友排序:按照拼音顺序对好友进行排序,兼容英文数字符号等 2.字母索引:右侧字母导航条,既可拖动也可点击,联动ListView滑动 三、实现 接下来就让我们一步步显示这个效果吧。 1.右侧字母索引的导航条 ...

    一、效果图展示



    二、功能特点

    1.好友排序:按照拼音顺序对好友进行排序,兼容英文数字符号等

    2.字母索引:右侧字母导航条,既可拖动也可点击,联动ListView滑动


    三、实现

    接下来就让我们一步步显示这个效果吧。

    1.右侧字母索引的导航条

    这个我们可以在网上找到很多类似的,你大可找一个自己喜欢的甚至自己写一个出来,这里我在网上找了一个带波浪效果的,看起来比较炫酷一点吧。

    这是原地址:https://github.com/AlexLiuSheng/AnimSideBar

    然后我把它导入到了我们项目中并修改了部分代码,以下是我项目中的SideBar.Java

    [java] view plain copy
    1. package com.afei.indexlistview;  
    2.   
    3. import android.content.Context;  
    4. import android.content.res.TypedArray;  
    5. import android.graphics.Canvas;  
    6. import android.graphics.Paint;  
    7. import android.util.AttributeSet;  
    8. import android.view.MotionEvent;  
    9. import android.widget.TextView;  
    10.   
    11. public class SideBar extends TextView {  
    12.     private String[] letters = new String[]{"A""B""C""D""E""F""G""H""I",  
    13.             "J""K""L""M""N""O""P""Q""R""S""T""U""V",  
    14.             "W""X""Y""Z""#"};  
    15.     private Paint textPaint;  
    16.     private Paint bigTextPaint;  
    17.     private Paint scaleTextPaint;  
    18.   
    19.     private Canvas canvas;  
    20.     private int itemH;  
    21.     private int w;  
    22.     private int h;  
    23.     /** 
    24.      * 普通情况下字体大小 
    25.      */  
    26.     float singleTextH;  
    27.     /** 
    28.      * 缩放离原始的宽度 
    29.      */  
    30.     private float scaleWidth;  
    31.     /** 
    32.      * 滑动的Y 
    33.      */  
    34.     private float eventY = 0;  
    35.     /** 
    36.      * 缩放的倍数 
    37.      */  
    38.     private int scaleSize = 1;  
    39.     /** 
    40.      * 缩放个数item,即开口大小 
    41.      */  
    42.     private int scaleItemCount = 6;  
    43.     private ISideBarSelectCallBack callBack;  
    44.   
    45.     public SideBar(Context context) {  
    46.         this(context, null);  
    47.     }  
    48.   
    49.     public SideBar(Context context, AttributeSet attrs) {  
    50.         this(context, attrs, 0);  
    51.     }  
    52.   
    53.     public SideBar(Context context, AttributeSet attrs, int defStyleAttr) {  
    54.         super(context, attrs, defStyleAttr);  
    55.         init(attrs);  
    56.     }  
    57.   
    58.     private void init(AttributeSet attrs) {  
    59.         if (attrs != null) {  
    60.             TypedArray ta = getContext().obtainStyledAttributes(attrs, R.styleable.SideBar);  
    61.             scaleSize = ta.getInteger(R.styleable.SideBar_scaleSize, 1);  
    62.             scaleItemCount = ta.getInteger(R.styleable.SideBar_scaleItemCount, 6);  
    63.             scaleWidth = ta.getDimensionPixelSize(R.styleable.SideBar_scaleWidth, dp(100));  
    64.             ta.recycle();  
    65.         }  
    66.         textPaint = new Paint(Paint.ANTI_ALIAS_FLAG);  
    67.         textPaint.setColor(getCurrentTextColor());  
    68.         textPaint.setTextSize(getTextSize());  
    69.         textPaint.setTextAlign(Paint.Align.CENTER);  
    70.         bigTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);  
    71.         bigTextPaint.setColor(getCurrentTextColor());  
    72.         bigTextPaint.setTextSize(getTextSize() * (scaleSize + 3));  
    73.         bigTextPaint.setTextAlign(Paint.Align.CENTER);  
    74.         scaleTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);  
    75.         scaleTextPaint.setColor(getCurrentTextColor());  
    76.         scaleTextPaint.setTextSize(getTextSize() * (scaleSize + 1));  
    77.         scaleTextPaint.setTextAlign(Paint.Align.CENTER);  
    78.     }  
    79.   
    80.     public void setDataResource(String[] data) {  
    81.         letters = data;  
    82.         invalidate();  
    83.     }  
    84.   
    85.     public void setOnStrSelectCallBack(ISideBarSelectCallBack callBack) {  
    86.         this.callBack = callBack;  
    87.     }  
    88.   
    89.     /** 
    90.      * 设置字体缩放比例 
    91.      * 
    92.      * @param scale 
    93.      */  
    94.     public void setScaleSize(int scale) {  
    95.         scaleSize = scale;  
    96.         invalidate();  
    97.     }  
    98.   
    99.     /** 
    100.      * 设置缩放字体的个数,即开口大小 
    101.      * 
    102.      * @param scaleItemCount 
    103.      */  
    104.     public void setScaleItemCount(int scaleItemCount) {  
    105.         this.scaleItemCount = scaleItemCount;  
    106.         invalidate();  
    107.     }  
    108.   
    109.     private int dp(int px) {  
    110.         final float scale = getContext().getResources().getDisplayMetrics().density;  
    111.         return (int) (px * scale + 0.5f);  
    112.     }  
    113.   
    114.     @Override  
    115.     public boolean onTouchEvent(MotionEvent event) {  
    116.         switch (event.getAction()) {  
    117.             case MotionEvent.ACTION_DOWN:  
    118.             case MotionEvent.ACTION_MOVE:  
    119.                 if (event.getX() > (w - getPaddingRight() - singleTextH - 10)) {  
    120.                     eventY = event.getY();  
    121.                     invalidate();  
    122.                     return true;  
    123.                 } else {  
    124.                     eventY = 0;  
    125.                     invalidate();  
    126.                     break;  
    127.                 }  
    128.             case MotionEvent.ACTION_CANCEL:  
    129.                 eventY = 0;  
    130.                 invalidate();  
    131.                 return true;  
    132.             case MotionEvent.ACTION_UP:  
    133.                 if (event.getX() > (w - getPaddingRight() - singleTextH - 10)) {  
    134.                     eventY = 0;  
    135.                     invalidate();  
    136.                     return true;  
    137.                 } else  
    138.                     break;  
    139.         }  
    140.         return super.onTouchEvent(event);  
    141.     }  
    142.   
    143.   
    144.     @Override  
    145.     protected void onDraw(Canvas canvas) {  
    146.         this.canvas = canvas;  
    147.         DrawView(eventY);  
    148.     }  
    149.   
    150.     private void DrawView(float y) {  
    151.         int currentSelectIndex = -1;  
    152.         if (y != 0) {  
    153.             for (int i = 0; i < letters.length; i++) {  
    154.                 float currentItemY = itemH * i;  
    155.                 float nextItemY = itemH * (i + 1);  
    156.                 if (y >= currentItemY && y < nextItemY) {  
    157.                     currentSelectIndex = i;  
    158.                     if (callBack != null) {  
    159.                         callBack.onSelectStr(currentSelectIndex, letters[i]);  
    160.                     }  
    161.                     //画大的字母  
    162.                     Paint.FontMetrics fontMetrics = bigTextPaint.getFontMetrics();  
    163.                     float bigTextSize = fontMetrics.descent - fontMetrics.ascent;  
    164.                     canvas.drawText(letters[i], w - getPaddingRight() - scaleWidth - bigTextSize, singleTextH + itemH * i, bigTextPaint);  
    165.                 }  
    166.             }  
    167.         }  
    168.         drawLetters(y, currentSelectIndex);  
    169.     }  
    170.   
    171.     private void drawLetters(float y, int index) {  
    172.         //第一次进来没有缩放情况,默认画原图  
    173.         if (index == -1) {  
    174.             w = getMeasuredWidth();  
    175.             h = getMeasuredHeight();  
    176.             itemH = h / letters.length;  
    177.             Paint.FontMetrics fontMetrics = textPaint.getFontMetrics();  
    178.             singleTextH = fontMetrics.descent - fontMetrics.ascent;  
    179.             for (int i = 0; i < letters.length; i++) {  
    180.                 canvas.drawText(letters[i], w - getPaddingRight(), singleTextH + itemH * i, textPaint);  
    181.             }  
    182.             //触摸的时候画缩放图  
    183.         } else {  
    184.             //遍历所有字母  
    185.             for (int i = 0; i < letters.length; i++) {  
    186.                 //要画的字母的起始Y坐标  
    187.                 float currentItemToDrawY = singleTextH + itemH * i;  
    188.                 float centerItemToDrawY;  
    189.                 if (index < i)  
    190.                     centerItemToDrawY = singleTextH + itemH * (index + scaleItemCount);  
    191.                 else  
    192.                     centerItemToDrawY = singleTextH + itemH * (index - scaleItemCount);  
    193.                 float delta = 1 - Math.abs((y - currentItemToDrawY) / (centerItemToDrawY - currentItemToDrawY));  
    194.                 float maxRightX = w - getPaddingRight();  
    195.                 //如果大于0,表明在y坐标上方  
    196.                 scaleTextPaint.setTextSize(getTextSize() + getTextSize() * delta);  
    197.                 float drawX = maxRightX - scaleWidth * delta;  
    198.                 //超出边界直接花在边界上  
    199.                 if (drawX > maxRightX)  
    200.                     canvas.drawText(letters[i], maxRightX, singleTextH + itemH * i, textPaint);  
    201.                 else  
    202.                     canvas.drawText(letters[i], drawX, singleTextH + itemH * i, scaleTextPaint);  
    203.             }  
    204.         }  
    205.     }  
    206.   
    207.     public interface ISideBarSelectCallBack {  
    208.         void onSelectStr(int index, String selectStr);  
    209.     }  
    210.   
    211. }  
    然后还有3个自定义的属性

    [html] view plain copy
    1. <?xml version="1.0" encoding="utf-8"?>  
    2. <resources>  
    3.     <declare-styleable name="SideBar">  
    4.         <attr name="scaleSize" format="integer"/>  
    5.         <attr name="scaleItemCount" format="integer"/>  
    6.         <attr name="scaleWidth" format="dimension"/>  
    7.     </declare-styleable>  
    8. </resources>  


    2.汉字转拼音工具类

    我们知道,java中是没有提供接口和方法让我们直接将汉字转成拼音的。

    这里,可以参见我的另一篇博客:Java/Android中汉字转拼音的两种方法,优劣比较
    然后在此我选择了使用第三方jar包的方式,因为它体积不大而且更加准确。以下是我的Cn2Spell.java

    [java] view plain copy
    1. package com.afei.indexlistview;  
    2.   
    3. import net.sourceforge.pinyin4j.PinyinHelper;  
    4. import net.sourceforge.pinyin4j.format.HanyuPinyinCaseType;  
    5. import net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat;  
    6. import net.sourceforge.pinyin4j.format.HanyuPinyinToneType;  
    7.   
    8. /** 
    9.  * 汉字转换位汉语拼音,英文字符不变 
    10.  */  
    11. public class Cn2Spell {  
    12.   
    13.     public static StringBuffer sb = new StringBuffer();  
    14.   
    15.     /** 
    16.      * 获取汉字字符串的首字母,英文字符不变 
    17.      * 例如:阿飞→af 
    18.      */  
    19.     public static String getPinYinHeadChar(String chines) {  
    20.         sb.setLength(0);  
    21.         char[] chars = chines.toCharArray();  
    22.         HanyuPinyinOutputFormat defaultFormat = new HanyuPinyinOutputFormat();  
    23.         defaultFormat.setCaseType(HanyuPinyinCaseType.LOWERCASE);  
    24.         defaultFormat.setToneType(HanyuPinyinToneType.WITHOUT_TONE);  
    25.         for (int i = 0; i < chars.length; i++) {  
    26.             if (chars[i] > 128) {  
    27.                 try {  
    28.                     sb.append(PinyinHelper.toHanyuPinyinStringArray(chars[i], defaultFormat)[0].charAt(0));  
    29.                 } catch (Exception e) {  
    30.                     e.printStackTrace();  
    31.                 }  
    32.             } else {  
    33.                 sb.append(chars[i]);  
    34.             }  
    35.         }  
    36.         return sb.toString();  
    37.     }  
    38.   
    39.     /** 
    40.      * 获取汉字字符串的第一个字母 
    41.      */  
    42.     public static String getPinYinFirstLetter(String str) {  
    43.         sb.setLength(0);  
    44.         char c = str.charAt(0);  
    45.         String[] pinyinArray = PinyinHelper.toHanyuPinyinStringArray(c);  
    46.         if (pinyinArray != null) {  
    47.             sb.append(pinyinArray[0].charAt(0));  
    48.         } else {  
    49.             sb.append(c);  
    50.         }  
    51.         return sb.toString();  
    52.     }  
    53.   
    54.     /** 
    55.      * 获取汉字字符串的汉语拼音,英文字符不变 
    56.      */  
    57.     public static String getPinYin(String chines) {  
    58.         sb.setLength(0);  
    59.         char[] nameChar = chines.toCharArray();  
    60.         HanyuPinyinOutputFormat defaultFormat = new HanyuPinyinOutputFormat();  
    61.         defaultFormat.setCaseType(HanyuPinyinCaseType.LOWERCASE);  
    62.         defaultFormat.setToneType(HanyuPinyinToneType.WITHOUT_TONE);  
    63.         for (int i = 0; i < nameChar.length; i++) {  
    64.             if (nameChar[i] > 128) {  
    65.                 try {  
    66.                     sb.append(PinyinHelper.toHanyuPinyinStringArray(nameChar[i], defaultFormat)[0]);  
    67.                 } catch (Exception e) {  
    68.                     e.printStackTrace();  
    69.                 }  
    70.             } else {  
    71.                 sb.append(nameChar[i]);  
    72.             }  
    73.         }  
    74.         return sb.toString();  
    75.     }  
    76.   
    77. }  

    3.让你的好友可以根据拼音来排序

    我们选择实现comparable接口,并重写comparaTo方法。以下是我的User.java

    [java] view plain copy
    1. package com.afei.indexlistview;  
    2.   
    3. /** 
    4.  * Created by Administrator on 2016/5/25. 
    5.  */  
    6. public class User implements Comparable<User> {  
    7.   
    8.     private String name; // 姓名  
    9.     private String pinyin; // 姓名对应的拼音  
    10.     private String firstLetter; // 拼音的首字母  
    11.   
    12.     public User() {  
    13.     }  
    14.   
    15.     public User(String name) {  
    16.         this.name = name;  
    17.         pinyin = Cn2Spell.getPinYin(name); // 根据姓名获取拼音  
    18.         firstLetter = pinyin.substring(01).toUpperCase(); // 获取拼音首字母并转成大写  
    19.         if (!firstLetter.matches("[A-Z]")) { // 如果不在A-Z中则默认为“#”  
    20.             firstLetter = "#";  
    21.         }  
    22.     }  
    23.   
    24.     public String getName() {  
    25.         return name;  
    26.     }  
    27.   
    28.     public String getPinyin() {  
    29.         return pinyin;  
    30.     }  
    31.   
    32.     public String getFirstLetter() {  
    33.         return firstLetter;  
    34.     }  
    35.   
    36.   
    37.     @Override  
    38.     public int compareTo(User another) {  
    39.         if (firstLetter.equals("#") && !another.getFirstLetter().equals("#")) {  
    40.             return 1;  
    41.         } else if (!firstLetter.equals("#") && another.getFirstLetter().equals("#")){  
    42.             return -1;  
    43.         } else {  
    44.             return pinyin.compareToIgnoreCase(another.getPinyin());  
    45.         }  
    46.     }  
    47. }  

    原理很简单,就是先根据首字母判断,首字母为“#”都放在最后,都为“#”或者都是字母时才根据拼音来比较排序


    4.万事俱备只欠东风,接下来就是组装这些东西了

    activity_main.xml布局文件

    [html] view plain copy
    1. <?xml version="1.0" encoding="utf-8"?>  
    2. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    3.     xmlns:tools="http://schemas.android.com/tools"  
    4.     android:layout_width="match_parent"  
    5.     android:layout_height="match_parent"  
    6.     tools:context="com.afei.indexlistview.MainActivity">  
    7.   
    8.     <ListView  
    9.         android:id="@+id/listView"  
    10.         android:layout_width="match_parent"  
    11.         android:layout_height="match_parent" />  
    12.   
    13.     <com.afei.indexlistview.SideBar  
    14.         android:id="@+id/side_bar"  
    15.         android:layout_width="match_parent"  
    16.         android:layout_height="match_parent"  
    17.         android:layout_alignParentRight="true"  
    18.         android:paddingRight="10dp"  
    19.         android:textColor="@color/colorAccent"  
    20.         android:textSize="15sp" />  
    21.   
    22. </RelativeLayout>  

    MainActivity.java

    [java] view plain copy
    1. package com.afei.indexlistview;  
    2.   
    3. import android.support.v7.app.AppCompatActivity;  
    4. import android.os.Bundle;  
    5. import android.widget.ListView;  
    6.   
    7. import java.util.ArrayList;  
    8. import java.util.Collections;  
    9.   
    10. public class MainActivity extends AppCompatActivity {  
    11.   
    12.     private ListView listView;  
    13.     private SideBar sideBar;  
    14.     private ArrayList<User> list;  
    15.   
    16.     @Override  
    17.     protected void onCreate(Bundle savedInstanceState) {  
    18.         super.onCreate(savedInstanceState);  
    19.         setContentView(R.layout.activity_main);  
    20.         initView();  
    21.         initData();  
    22.     }  
    23.   
    24.     private void initView() {  
    25.         listView = (ListView) findViewById(R.id.listView);  
    26.         sideBar = (SideBar) findViewById(R.id.side_bar);  
    27.         sideBar.setOnStrSelectCallBack(new SideBar.ISideBarSelectCallBack() {  
    28.             @Override  
    29.             public void onSelectStr(int index, String selectStr) {  
    30.                 for (int i = 0; i < list.size(); i++) {  
    31.                     if (selectStr.equalsIgnoreCase(list.get(i).getFirstLetter())) {  
    32.                         listView.setSelection(i); // 选择到首字母出现的位置  
    33.                         return;  
    34.                     }  
    35.                 }  
    36.             }  
    37.         });  
    38.     }  
    39.   
    40.     private void initData() {  
    41.         list = new ArrayList<>();  
    42.         list.add(new User("亳州")); // 亳[bó]属于不常见的二级汉字  
    43.         list.add(new User("大娃"));  
    44.         list.add(new User("二娃"));  
    45.         list.add(new User("三娃"));  
    46.         list.add(new User("四娃"));  
    47.         list.add(new User("五娃"));  
    48.         list.add(new User("六娃"));  
    49.         list.add(new User("七娃"));  
    50.         list.add(new User("喜羊羊"));  
    51.         list.add(new User("美羊羊"));  
    52.         list.add(new User("懒羊羊"));  
    53.         list.add(new User("沸羊羊"));  
    54.         list.add(new User("暖羊羊"));  
    55.         list.add(new User("慢羊羊"));  
    56.         list.add(new User("灰太狼"));  
    57.         list.add(new User("红太狼"));  
    58.         list.add(new User("孙悟空"));  
    59.         list.add(new User("黑猫警长"));  
    60.         list.add(new User("舒克"));  
    61.         list.add(new User("贝塔"));  
    62.         list.add(new User("海尔"));  
    63.         list.add(new User("阿凡提"));  
    64.         list.add(new User("邋遢大王"));  
    65.         list.add(new User("哪吒"));  
    66.         list.add(new User("没头脑"));  
    67.         list.add(new User("不高兴"));  
    68.         list.add(new User("蓝皮鼠"));  
    69.         list.add(new User("大脸猫"));  
    70.         list.add(new User("大头儿子"));  
    71.         list.add(new User("小头爸爸"));  
    72.         list.add(new User("蓝猫"));  
    73.         list.add(new User("淘气"));  
    74.         list.add(new User("叶峰"));  
    75.         list.add(new User("楚天歌"));  
    76.         list.add(new User("江流儿"));  
    77.         list.add(new User("Tom"));  
    78.         list.add(new User("Jerry"));  
    79.         list.add(new User("12345"));  
    80.         list.add(new User("54321"));  
    81.         list.add(new User("_(:з」∠)_"));  
    82.         list.add(new User("……%¥#¥%#"));  
    83.         Collections.sort(list); // 对list进行排序,需要让User实现Comparable接口重写compareTo方法  
    84.         SortAdapter adapter = new SortAdapter(this, list);  
    85.         listView.setAdapter(adapter);  
    86.     }  
    87. }  
    这里负责初始化UI和数据,并且实现滑动或选择字母索引时的回调接口。既然用到了ListView,我们就还需要一个适配器。

    SortAdapter.java

    [java] view plain copy
    1. package com.afei.indexlistview;  
    2.   
    3. import android.content.Context;  
    4. import android.view.LayoutInflater;  
    5. import android.view.View;  
    6. import android.view.ViewGroup;  
    7. import android.widget.BaseAdapter;  
    8. import android.widget.TextView;  
    9.   
    10. import java.util.List;  
    11.   
    12. public class SortAdapter extends BaseAdapter{  
    13.   
    14.     private List<User> list = null;  
    15.     private Context mContext;  
    16.   
    17.     public SortAdapter(Context mContext, List<User> list) {  
    18.         this.mContext = mContext;  
    19.         this.list = list;  
    20.     }  
    21.   
    22.     public int getCount() {  
    23.         return this.list.size();  
    24.     }  
    25.   
    26.     public Object getItem(int position) {  
    27.         return list.get(position);  
    28.     }  
    29.   
    30.     public long getItemId(int position) {  
    31.         return position;  
    32.     }  
    33.   
    34.     public View getView(final int position, View view, ViewGroup arg2) {  
    35.         ViewHolder viewHolder;  
    36.         final User user = list.get(position);  
    37.         if (view == null) {  
    38.             viewHolder = new ViewHolder();  
    39.             view = LayoutInflater.from(mContext).inflate(R.layout.item, null);  
    40.             viewHolder.name = (TextView) view.findViewById(R.id.name);  
    41.             viewHolder.catalog = (TextView) view.findViewById(R.id.catalog);  
    42.             view.setTag(viewHolder);  
    43.         } else {  
    44.             viewHolder = (ViewHolder) view.getTag();  
    45.         }  
    46.   
    47.         //根据position获取首字母作为目录catalog  
    48.         String catalog = list.get(position).getFirstLetter();  
    49.   
    50.         //如果当前位置等于该分类首字母的Char的位置 ,则认为是第一次出现  
    51.         if(position == getPositionForSection(catalog)){  
    52.             viewHolder.catalog.setVisibility(View.VISIBLE);  
    53.             viewHolder.catalog.setText(user.getFirstLetter().toUpperCase());  
    54.         }else{  
    55.             viewHolder.catalog.setVisibility(View.GONE);  
    56.         }  
    57.   
    58.         viewHolder.name.setText(this.list.get(position).getName());  
    59.   
    60.         return view;  
    61.   
    62.     }  
    63.   
    64.     final static class ViewHolder {  
    65.         TextView catalog;  
    66.         TextView name;  
    67.     }  
    68.   
    69.     /** 
    70.      * 获取catalog首次出现位置 
    71.      */  
    72.     public int getPositionForSection(String catalog) {  
    73.         for (int i = 0; i < getCount(); i++) {  
    74.             String sortStr = list.get(i).getFirstLetter();  
    75.             if (catalog.equalsIgnoreCase(sortStr)) {  
    76.                 return i;  
    77.             }  
    78.         }  
    79.         return -1;  
    80.     }  
    81.   
    82. }  
    适配器还用到了一个布局,即


    item.xml

    [html] view plain copy
    1. <?xml version="1.0" encoding="utf-8"?>  
    2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    3.     android:layout_width="match_parent"  
    4.     android:layout_height="wrap_content"  
    5.     android:gravity="center_vertical"  
    6.     android:orientation="vertical" >  
    7.   
    8.     <TextView  
    9.         android:id="@+id/catalog"  
    10.         android:layout_width="match_parent"  
    11.         android:layout_height="match_parent"  
    12.         android:background="#E0E0E0"  
    13.         android:textColor="#454545"  
    14.         android:textSize="20sp"  
    15.         android:padding="10dp"/>  
    16.   
    17.     <TextView  
    18.         android:id="@+id/name"  
    19.         android:layout_width="match_parent"  
    20.         android:layout_height="match_parent"  
    21.         android:gravity="center_vertical"  
    22.         android:textColor="#336598"  
    23.         android:textSize="16sp"  
    24.         android:padding="10dp"/>  
    25.   
    26. </LinearLayout>  
    布局有两部分,一个是目录,即A,B,C,D这样的索引,仅当该目录下的第一项出现时才显示;一个则是姓名

    四、项目地址

    Git地址:http://git.oschina.net/afei_/IndexListView

    展开全文
  • 在manifest添加以下权限 uses-permission android:name="android.permission.READ_CONTACTS" />

    在manifest添加以下权限

    <uses-permission android:name="android.permission.READ_CONTACTS" />
    
    
    
    

    /**
         * 获取通讯录列表
         * @param s 查询条件,null时为查询所有联系人。
         *          s = "刘"则查询所有包含刘字的联系人
         */
        private void getCallList(final String s) {
            //新开线程,防止通讯录太多联系人,卡顿
            Thread thread = new Thread(new Runnable() {
                @Override
                public void run() {
                    String[] cols = {ContactsContract.PhoneLookup.DISPLAY_NAME,
                            ContactsContract.CommonDataKinds.Phone.NUMBER,
                            ContactsContract.CommonDataKinds.Phone.PHOTO_ID,
                            ContactsContract.CommonDataKinds.Phone.CONTACT_ID};
                    Cursor cursor;
                    if (s!=null){
                        //设置查询条件
                        String selection = ContactsContract.PhoneLookup.DISPLAY_NAME + " like '%" + s
                                + "%' or " + ContactsContract.CommonDataKinds.Phone.NUMBER + " like '%" + s + "%'";
                        //ContactsContract.CommonDataKinds.Phone.SORT_KEY_PRIMARY 这个参数是让查询结果按字母排序
                        cursor = getContext().getContentResolver()
                                .query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
                                        cols, selection, null, ContactsContract.CommonDataKinds.Phone.SORT_KEY_PRIMARY);
                    }else {
                        cursor = getContext().getContentResolver()
                                .query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
                                        cols, null, null, ContactsContract.CommonDataKinds.Phone.SORT_KEY_PRIMARY);
                    }
                    int nameFieldColumnIndex = cursor.getColumnIndex(ContactsContract.PhoneLookup.DISPLAY_NAME);
                    int contactIdFieldColumnIndex = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.CONTACT_ID);
                    int numberFieldColumnIndex = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER);
                    int photoFieldColumnIndex = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.PHOTO_ID);
                    for (int i = 0; i < cursor.getCount(); i++) {
                        cursor.moveToPosition(i);
                        String name = cursor.getString(nameFieldColumnIndex);//联系人名称
                        Long contactId = cursor.getLong(contactIdFieldColumnIndex);//联系人ID
                        Long photoId = cursor.getLong(photoFieldColumnIndex);//联系人头像ID
                        String phoneNum = cursor.getString(numberFieldColumnIndex);//联系人手机号
                        Log.i("Msg","name:"+name);
                        Log.i("Msg","contactId:"+contactId);
                        Log.i("Msg","photoId:"+photoId);
                        Log.i("Msg","phoneNum:"+phoneNum);
                        //在此处执行相应的存储操作,之后会查询下一条联系人信息
                    }
                    cursor.close();
                    //此处执行查询完毕要执行的操作,若要更新UI,要使用handle
                }
            });
            thread.start();
      

    可以通过头像id和联系人id获取联系人的头像
    private Bitmap getBitmap(Long photoId, Long contactId) {
            Bitmap contactPhoto;//photoid 大于0 表示联系人有头像 如果没有给此人设置头像则给他一个默认的
            if(photoId > 0 ) {
                Uri uri = ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI,contactId);
                InputStream input = ContactsContract.Contacts.openContactPhotoInputStream(getContentResolver(), uri);
                contactPhoto = BitmapFactory.decodeStream(input);
            }else {
                contactPhoto = BitmapFactory.decodeResource(getResources(), R.drawable.icon_shareapp);
            }
            return contactPhoto;
        }


    
    展开全文
  • 2019独角兽企业重金招聘Python工程师标准>>> ...

    一般来说,获取按名称排序结果的方法有两种。一、在获取数据的时候,就已经排好序。二、获取完数据,再将list排序,这种情况需要导入拼音外部包。

    这里只介绍第一种。看代码:

    Cursor phoneCursor = resolver.query(Phone.CONTENT_URI,ConstUtil.PHONES_PROJECTION, null, null, Phone.DISPLAY_NAME + " COLLATE LOCALIZED");



    关键点在于最后的  
    COLLATE LOCALIZED

    转载于:https://my.oschina.net/zjchase/blog/180677

    展开全文
  • Android通讯录数据库介绍与基本操作(增删改查) 2014年2月21日 Android通讯录管理总结 这几天导师安排我一个任务就是研究一下Android通讯录获取联系人、通话记录、短信的方法,还有看看不同Android版本...
  • Android通讯录管理(获取联系人、通话记录、短信消息) 2014年2月26日 通讯录开发研究学习 前言:前阵子主要是记录了如何对联系人的一些操作,比如搜索,全选、反选和删除等在实际开发中可能需要实现的...
  • 项目中经常会用到一些获取手机里通讯录的功能,这边对其进行了排序 // 读取通讯录 private void readMail() { mallBuffer.setLength(0); mallBuffer.append("["); // 获取手机联系人:最后一个筛选...
  • 本文给出了Android读取通讯录联系人的一般方法,且在读取Android通讯录联系人时候,将结果有序化(按照联系人姓名的首字符依次顺序读取:A ~ Z)。 读取的结果如图所示: 现给出实现该种Android...
  • 有研究过手机通讯录数据的童鞋肯定知道一个数据库文件:目前是contact2.db(哥的手机是Android4.04的) 在此路径下可以找到:/data/data/com.android.providers.contacts/databases/contact2.db 将其导入可视化...
  • Android仿微信通讯录

    2019-09-24 15:19:27
    Android仿微信通讯录 分3部: 1、listview实现显示头像、名字(太简单,这里就不写了) 通讯录页面xml布局代码: <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:...
  • 主要使用Sticky-Header-RecyclerView实现效果。
  • android系统1.6中 读取联系人:   cursor = cr.query(People.CONTENT_URI, null, null, null, "name desc"); //取得联系人名次 name = cursor.getString(cursor.getColumnIndex(ContactsContract....
  • Android通讯录模糊查询搜索(号码,姓名,首字母简拼,全拼),批量选取联系人  公司最近的项目中遇到一个需求需要读取通讯录联系人,需要支持对联系人的模糊查询及批量选取,网上找了好几个例子,模糊查询这块...
  • Android系统架构的最上层是应用程序层,其上包含各种与用户相关的应用程序。这些应用程序基本都是由Java语言编写的,包括系统桌面、电子邮件客户端、SMS短信、地图、电源管理、电话、联系人等系统应用程序,以及各种...
1 2 3 4 5 ... 20
收藏数 2,974
精华内容 1,189