Android获取手机电话簿信息

1、Activity:

/**
 * Created by admin on 2015/9/22.
 */
public class PhoneBookActivity extends Activity {
    private static final String TAG = "PhoneBookActivity";
    private IndexableListView phoneListView;
    // 电话本数据List
    ArrayList<PhoneInfo> phoneInfosList;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.test_phone_main);
        phoneListView = (IndexableListView) findViewById(R.id.phoneListView);
        phoneInfosList = new ArrayList<>();
        // 初始化数据
        getPhoneContacts();

        // 按字典序进行排序
        Collections.sort(phoneInfosList, new Comparator<PhoneInfo>() {
            @Override
            public int compare(PhoneInfo lhs, PhoneInfo rhs) {
                return lhs.getFirstLetter() - rhs.getFirstLetter();
            }
        });

        // 判断ListView中的每个字母索引的头部
        PhoneInfo.tagIsHead(phoneInfosList);

        PhoneAdapter adapter = new PhoneAdapter(this);
        phoneListView.setAdapter(adapter);
        phoneListView.setFastScrollEnabled(true); // 设置快速滑动,这一步不可少
    }

    private class PhoneAdapter extends BaseAdapter implements SectionIndexer {
        // 定义索引列表
        private String mSections = "#ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        LayoutInflater layoutInflater;

        public PhoneAdapter (Context context) {
            layoutInflater = LayoutInflater.from(context);
        }

        @Override
        public int getCount() {
            return phoneInfosList != null ? phoneInfosList.size() : 0;
        }

        @Override
        public PhoneInfo getItem(int position) {
            return phoneInfosList != null ? phoneInfosList.get(position) : null;
        }

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

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            ViewHolder viewHolder;
            if (convertView == null) {
                convertView = layoutInflater.inflate(R.layout.phone_item, parent, false);
                viewHolder = new ViewHolder();
                viewHolder.img_phonePhoto = (ImageView) convertView.findViewById(R.id.img_phonePhoto);
                viewHolder.txt_contactName= (TextView) convertView.findViewById(R.id.txt_contactName);
                viewHolder.txt_phoneNumber= (TextView) convertView.findViewById(R.id.txt_phoneNumber);
                viewHolder.txtHeadLetter  = (TextView) convertView.findViewById(R.id.txtHeadLetter);
                convertView.setTag(viewHolder);
            } else {
                viewHolder = (ViewHolder) convertView.getTag();
            }

            try {
                PhoneInfo info = getItem(position);
                viewHolder.img_phonePhoto.setImageBitmap(info.getContactPhoto());
                viewHolder.txt_contactName.setText(info.getContactName());
                viewHolder.txt_phoneNumber.setText(info.getPhoneNumber());
                if (info.isHead()) {
                    viewHolder.txtHeadLetter.setText(String.valueOf(info.getFirstLetter()));
                    viewHolder.txtHeadLetter.setVisibility(View.VISIBLE);
                } else {
                    viewHolder.txtHeadLetter.setVisibility(View.GONE);
                }
            } catch (Exception e) {
                Log.e(TAG, e.toString());
            }
            return convertView;
        }

        @Override
        public int getPositionForSection(int section) {
            // 如果当前部分没有item,则之前的部分将被选择
            for (int i = section; i >= 0; i--) {
                for (int j = 0; j < getCount(); j++) {
                    if (i == 0) { // #
                        // For numeric section 数字
                        for (int k = 0; k <= 9; k++) {// 1...9
                            // 字符串第一个字符与1~9之间的数字进行匹配
                            if (StringMatcher.match(String.valueOf(getItem(j).getFirstLetter()), String.valueOf(k)))
                                return j;
                        }
                    } else { // A~Z
                        // getItem即获取ListView中的数据,并与索引进行匹配,找到Item的位置
                        if (StringMatcher.match(String.valueOf(getItem(j).getFirstLetter()),
                                String.valueOf(mSections.charAt(i))))
                            return j;
                    }
                }
            }
            return 0;
        }

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

        @Override
        public Object[] getSections() {
            String[] sections = new String[mSections.length()];
            for (int i = 0; i < mSections.length(); i++)
                sections[i] = String.valueOf(mSections.charAt(i));
            return sections;
        }

        class ViewHolder {
            ImageView img_phonePhoto;
            TextView txt_contactName;
            TextView txt_phoneNumber;
            TextView txtHeadLetter;
        }
    }

    // 获取通讯录:
    /**得到手机通讯录联系人信息**/
    private void getPhoneContacts() {
        ContentResolver resolver = this.getContentResolver();
        // 获取手机联系人
        Cursor phoneCursor = resolver.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
                PhoneInfo.PHONES_PROJECTION, null, null, null);
        if (phoneCursor != null) {
            while (phoneCursor.moveToNext()) {

                //得到手机号码
                String phoneNumber = phoneCursor.getString(PhoneInfo.PHONES_NUMBER_INDEX);
                //当手机号码为空的或者为空字段 跳过当前循环
                if (TextUtils.isEmpty(phoneNumber))
                    continue;
                //得到联系人名称
                String contactName = phoneCursor.getString(PhoneInfo.PHONES_DISPLAY_NAME_INDEX);
                //得到联系人ID
                Long contactid = phoneCursor.getLong(PhoneInfo.PHONES_CONTACT_ID_INDEX);
                //得到联系人头像ID
                Long photoid = phoneCursor.getLong(PhoneInfo.PHONES_PHOTO_ID_INDEX);

                phoneInfosList.add(new PhoneInfo(phoneNumber, contactName, contactid, photoid, resolver, this));
            }

            phoneCursor.close();
        }
    }
}

2、使用开源项目中自定义的ListView:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.woozzu.android.widget.IndexableListView
        android:id="@+id/phoneListView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"></com.woozzu.android.widget.IndexableListView>

</LinearLayout>

/**
 * 自定义索引列表
 */
public class IndexableListView extends ListView {

    // 是否允许快速滑动
    private boolean mIsFastScrollEnabled = false;
    // 索引条
    private IndexScroller mScroller = null;
    private GestureDetector mGestureDetector = null;

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

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

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

    @Override
    public boolean isFastScrollEnabled() {
        return mIsFastScrollEnabled;
    }

    // 初始化Scroller
    @Override
    public void setFastScrollEnabled(boolean enabled) {
        mIsFastScrollEnabled = enabled;
        if (mIsFastScrollEnabled) {
            if (mScroller == null)
                mScroller = new IndexScroller(getContext(), this);
        } else {
            if (mScroller != null) {
                mScroller.hide();
                mScroller = null;
            }
        }
    }

    @Override
    public void draw(Canvas canvas) {
        super.draw(canvas);

        // 调用Scroller的绘制函数
        // Overlay index bar
        if (mScroller != null)
            mScroller.draw(canvas);
    }

    // 处理触摸事件
    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        // Intercept ListView's touch event
        // 如果触摸事件发生在Scroller上,则屏蔽掉ListView上的触摸事件
        if (mScroller != null && mScroller.onTouchEvent(ev))
            return true;

        // 当ListView发生滑动时,显示Scroller
        if (mGestureDetector == null) {
            // 创建一个GestureDetector
            mGestureDetector = new GestureDetector(getContext(),
            new GestureDetector.SimpleOnGestureListener() {
                @Override
                public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
                    // 显示索引条
                    mScroller.show();
                    return super.onFling(e1, e2, velocityX, velocityY);
                }
            });
        }
        mGestureDetector.onTouchEvent(ev);

        return super.onTouchEvent(ev);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        return true;
    }

    // 设置Adapter
    @Override
    public void setAdapter(ListAdapter adapter) {
        super.setAdapter(adapter);
        if (mScroller != null)
            mScroller.setAdapter(adapter);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        if (mScroller != null)
            mScroller.onSizeChanged(w, h, oldw, oldh);
    }

}

3、自定义绘制右边的索引条:

/**
 * 右侧的索引条
 */
public class IndexScroller {

   private float mIndexbarWidth; // 索引条宽度
   private float mIndexbarMargin; // 索引条外边距
   private float mPreviewPadding; //
   private float mDensity; // 密度
   private float mScaledDensity; // 缩放密度
   private float mAlphaRate; // 透明度
   private int mState = STATE_HIDDEN; // 状态
   private int mListViewWidth; // ListView宽度
   private int mListViewHeight; // ListView高度
   private int mCurrentSection = -1; // 当前部分
   private boolean mIsIndexing = false; // 是否正在索引
   private ListView mListView = null;
   private SectionIndexer mIndexer = null;
   private String[] mSections = null;
   private RectF mIndexbarRect;

   // 4种显示状态(已隐藏、正在显示、已显示、正在隐藏)
   private static final int STATE_HIDDEN = 0;
   private static final int STATE_SHOWING = 1;
   private static final int STATE_SHOWN = 2;
   private static final int STATE_HIDING = 3;

   public IndexScroller(Context context, ListView lv) {
      mDensity = context.getResources().getDisplayMetrics().density;
      mScaledDensity = context.getResources().getDisplayMetrics().scaledDensity;
      mListView = lv;
      setAdapter(mListView.getAdapter());

      // 设置索引条宽度
      mIndexbarWidth = 20 * mDensity; // 索引条宽度
      mIndexbarMargin = 10 * mDensity;// 索引条间距
      mPreviewPadding = 5 * mDensity; // 内边距
   }

    // Scroller控件绘制函数
   public void draw(Canvas canvas) {
      if (mState == STATE_HIDDEN)
         return;

      // mAlphaRate determines the rate of opacity(透明度)
      Paint indexbarPaint = new Paint();
      indexbarPaint.setColor(Color.BLACK);
      indexbarPaint.setAlpha((int) (64 * mAlphaRate));
        // 设置抗锯齿效果
        indexbarPaint.setSubpixelText(true);
      indexbarPaint.setAntiAlias(true);
      // 画右侧字母索引的圆角矩形
      canvas.drawRoundRect(mIndexbarRect, 5 * mDensity, 5 * mDensity, indexbarPaint);

      if (mSections != null && mSections.length > 0) {
         // Preview is shown when mCurrentSection is set
            // 绘制选中时中间突出显示的TextView
         if (mCurrentSection >= 0) {
            Paint previewPaint = new Paint(); // 用来绘画所以条背景的画笔
            previewPaint.setColor(Color.BLACK);// 设置画笔颜色为黑色
            previewPaint.setAlpha(96); // 设置透明度
            previewPaint.setAntiAlias(true);// 设置抗锯齿
            previewPaint.setShadowLayer(3, 0, 0, Color.argb(64, 0, 0, 0)); // 设置阴影层

            Paint previewTextPaint = new Paint(); // 用来绘画索引字母的画笔
            previewTextPaint.setColor(Color.WHITE); // 设置画笔为白色
            previewTextPaint.setAntiAlias(true); // 设置抗锯齿
            previewTextPaint.setTextSize(50 * mScaledDensity); // 设置字体大小

            // 文本的宽度
            float previewTextWidth = previewTextPaint.measureText(mSections[mCurrentSection]);

                // 计算字体的大小
            float previewSize = 2 * mPreviewPadding + previewTextPaint.descent() - previewTextPaint.ascent();
            RectF previewRect = new RectF(
                  (mListViewWidth  - previewSize) / 2,
                  (mListViewHeight - previewSize) / 2,
                  (mListViewWidth  - previewSize) / 2 + previewSize,
                  (mListViewHeight - previewSize) / 2 + previewSize);

            // 中间索引的那个框
            canvas.drawRoundRect(previewRect, 5 * mDensity, 5 * mDensity, previewPaint);
            // 绘画索引字母
            canvas.drawText(
                  mSections[mCurrentSection],
                  previewRect.left + (previewSize - previewTextWidth) / 2 - 1,
                  previewRect.top + mPreviewPadding - previewTextPaint.ascent() + 1,
                  previewTextPaint);
         }

         // 绘画右侧索引条的字母
         Paint indexPaint = new Paint();
         indexPaint.setColor(Color.WHITE);
         indexPaint.setAlpha((int) (255 * mAlphaRate));
         indexPaint.setAntiAlias(true);
         indexPaint.setTextSize(12 * mScaledDensity);

         float sectionHeight = (mIndexbarRect.height() - 2 * mIndexbarMargin) / mSections.length;
         float paddingTop = (sectionHeight - (indexPaint.descent() - indexPaint.ascent())) / 2;
         for (int i = 0; i < mSections.length; i++) {
            float paddingLeft = (mIndexbarWidth - indexPaint.measureText(mSections[i])) / 2;
            canvas.drawText(mSections[i], mIndexbarRect.left + paddingLeft,
                  mIndexbarRect.top + mIndexbarMargin + sectionHeight * i + paddingTop - indexPaint.ascent(), indexPaint);
         }
      }
   }

    // 响应触摸事件
   public boolean onTouchEvent(MotionEvent ev) {
      switch (ev.getAction()) {
         case MotionEvent.ACTION_DOWN: // 按下,开始索引
            // If down event occurs inside index bar region, start indexing
            if (mState != STATE_HIDDEN && contains(ev.getX(), ev.getY())) {
               setState(STATE_SHOWN);

               // It demonstrates that the motion event started from index bar
               mIsIndexing = true;
               // Determine which section the point is in, and move the list to
               // that section
               mCurrentSection = getSectionByPoint(ev.getY());
               mListView.setSelection(mIndexer.getPositionForSection(mCurrentSection));
               return true;
            }
            break;
         case MotionEvent.ACTION_MOVE: // 移动
            if (mIsIndexing) {
               // If this event moves inside index bar
               if (contains(ev.getX(), ev.getY())) {
                  // Determine which section the point is in, and move the
                  // list to that section
                  mCurrentSection = getSectionByPoint(ev.getY());
                  mListView.setSelection(mIndexer.getPositionForSection(mCurrentSection));
               }
               return true;
            }
            break;
         case MotionEvent.ACTION_UP: // 抬起
            if (mIsIndexing) {
               mIsIndexing = false;
               mCurrentSection = -1;
            }
            if (mState == STATE_SHOWN)
               setState(STATE_HIDING);
            break;
      }
      return false;
   }

   public void onSizeChanged(int w, int h, int oldw, int oldh) {
      mListViewWidth = w;
      mListViewHeight = h;
        // left, top, right , bottom
      mIndexbarRect = new RectF(w - mIndexbarMargin - mIndexbarWidth, mIndexbarMargin, w - mIndexbarMargin, h - mIndexbarMargin);
   }

   // 显示
   public void show() {
      if (mState == STATE_HIDDEN)
         setState(STATE_SHOWING);
      else if (mState == STATE_HIDING)
         setState(STATE_HIDING);
   }

   // 隐藏
   public void hide() {
      if (mState == STATE_SHOWN)
         setState(STATE_HIDING);
   }

   // 注意此限制,所以自定义Adapter一定注意implement SectionIndexer接口
   public void setAdapter(Adapter adapter) {
      if (adapter instanceof SectionIndexer) {
         mIndexer = (SectionIndexer) adapter;
         mSections = (String[]) mIndexer.getSections();
      }
   }

   // 设置显示状态
   private void setState(int state) {
      if (state < STATE_HIDDEN || state > STATE_HIDING)
         return;

        // 最终都是通过Handler进行更新
      mState = state;
      switch (mState) {
         case STATE_HIDDEN:
            // Cancel any fade effect
            // 取消渐退的效果
            mHandler.removeMessages(0);
            break;
         case STATE_SHOWING:
            // Start to fade in
            // 开始渐进效果
            mAlphaRate = 0;
            fade(0);
            break;
         case STATE_SHOWN:
            // Cancel any fade effect
            // 取消渐退的效果
            mHandler.removeMessages(0);
            break;
         case STATE_HIDING:
            // Start to fade out after three seconds
            // 隐藏3秒钟
            mAlphaRate = 1;
            fade(3000);
            break;
      }
   }

    // 判断触摸点是否在Scroller控件上
   private boolean contains(float x, float y) {
      // Determine if the point is in index bar region, which includes the
      // right margin of the bar
      return (x >= mIndexbarRect.left && y >= mIndexbarRect.top && y <= mIndexbarRect.top + mIndexbarRect.height());
   }

   private int getSectionByPoint(float y) {
      if (mSections == null || mSections.length == 0)
         return 0;
      if (y < mIndexbarRect.top + mIndexbarMargin)
         return 0;
      if (y >= mIndexbarRect.top + mIndexbarRect.height() - mIndexbarMargin)
         return mSections.length - 1;
      return (int) ((y - mIndexbarRect.top - mIndexbarMargin) / ((mIndexbarRect
            .height() - 2 * mIndexbarMargin) / mSections.length));
   }

    // 延时显示fade效果
   private void fade(long delay) {
      mHandler.removeMessages(0);
      mHandler.sendEmptyMessageAtTime(0, SystemClock.uptimeMillis() + delay);
   }

    // 处理进度条View的更新操作
   private Handler mHandler = new Handler() {

      @Override
      public void handleMessage(Message msg) {
         super.handleMessage(msg);

         switch (mState) {
            case STATE_SHOWING:
               // Fade in effect
               // 淡进效果
               mAlphaRate += (1 - mAlphaRate) * 0.2;
               if (mAlphaRate > 0.9) {
                  mAlphaRate = 1;
                  setState(STATE_SHOWN);
               }
                    // 请求重绘ListView
               mListView.invalidate();
               fade(10);
               break;
            case STATE_SHOWN:
               // If no action, hide automatically
               setState(STATE_HIDING);
               break;
            case STATE_HIDING:
               // Fade out effect
               // 淡出效果
               mAlphaRate -= mAlphaRate * 0.2;
               if (mAlphaRate < 0.1) {
                  mAlphaRate = 0;
                  setState(STATE_HIDDEN);
               }

               mListView.invalidate();
               fade(10);
               break;
         }
      }

   };
}



4、ListView的工具类,用来匹配字符:

public class StringMatcher {

   // 这些变量是韩文,小巫也不知道是什么意思,有谁懂的马上联系我啊
   private final static char KOREAN_UNICODE_START = '가'; // 韩文字符编码开始?
   private final static char KOREAN_UNICODE_END = '힣';      // 韩文字符编码结束?
   private final static char KOREAN_UNIT = '까' - '가';   // 不知道是啥?
   // 韩文的一些字符初始化
   private final static char[] KOREAN_INITIAL = { 'ㄱ', 'ㄲ', 'ㄴ', 'ㄷ', 'ㄸ',
         'ㄹ', 'ㅁ', 'ㅂ', 'ㅃ', 'ㅅ', 'ㅆ', 'ㅇ', 'ㅈ', 'ㅉ', 'ㅊ', 'ㅋ', 'ㅌ', 'ㅍ',
         'ㅎ' };


   /**
    * 字符匹配
    * @param value    需要keyword匹配的字符串
    * @param keyword #ABCDEFGHIJKLMNOPQRSTUVWXYZ中的一个
    * @return
    */
   public static boolean match(String value, String keyword) {
      if (value == null || keyword == null)
         return false;
      if (keyword.length() > value.length())
         return false;

      int i = 0, j = 0;
      do {
         // 如果是韩文字符并且在韩文初始数组里面
         if (isKorean(value.charAt(i)) && isInitialSound(keyword.charAt(j))) {
            if (keyword.charAt(j) == getInitialSound(value.charAt(i))) {
               i++;
               j++;
            } else if (j > 0)
               break;
            else
               i++;
         } else {
            // 逐个字符匹配
            if (keyword.charAt(j) == value.charAt(i)) {
               i++;
               j++;
            } else if (j > 0)
               break;
            else
               i++;
         }
      } while (i < value.length() && j < keyword.length());
      // 如果最后j等于keyword的长度说明匹配成功
      return (j == keyword.length()) ? true : false;
   }

   // 判断字符是否在韩文字符编码范围内
   private static boolean isKorean(char c) {
      if (c >= KOREAN_UNICODE_START && c <= KOREAN_UNICODE_END)
         return true;
      return false;
   }

   // 判断是否在韩文字符里面
   private static boolean isInitialSound(char c) {
      for (char i : KOREAN_INITIAL) {
         if (c == i)
            return true;
      }
      return false;
   }

   // 获得韩文初始化字符数组里面的一个字符
   private static char getInitialSound(char c) {
      return KOREAN_INITIAL[(c - KOREAN_UNICODE_START) / KOREAN_UNIT];
   }
}

5、 电话信息记录类:

/**
 * Created by admin on 2015/9/21.
 */
public class PhoneInfo {
    /** 查询通讯录相关参数 **/
    public static final String[] PHONES_PROJECTION = new String[] {
            ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME, ContactsContract.CommonDataKinds.Phone.NUMBER,
            ContactsContract.CommonDataKinds.Phone.PHOTO_ID, ContactsContract.CommonDataKinds.Phone.CONTACT_ID };
    public final static int PHONES_DISPLAY_NAME_INDEX = 0;
    public final static int PHONES_NUMBER_INDEX       = 1;
    public final static int PHONES_PHOTO_ID_INDEX     = 2;
    public final static int PHONES_CONTACT_ID_INDEX   = 3;

    private String contactName;
    private String phoneNumber;
    private Long contactid;
    private Long photoid;
    private Bitmap contactPhoto;
    private char firstLetter; // contactName的首字母(大写)

    private boolean isHead; // 判断是否是一个索引的首元素

    // 获取contactName首字母的相关参数
    private final static int[] li_SecPosValue = { 1601, 1637, 1833, 2078, 2274,
            2302, 2433, 2594, 2787, 3106, 3212, 3472, 3635, 3722, 3730, 3858,
            4027, 4086, 4390, 4558, 4684, 4925, 5249, 5590 };
    private final static String[] lc_FirstLetter = { "A", "B", "C", "D", "E",
            "F", "G", "H", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S",
            "T", "W", "X", "Y", "Z" };

    public PhoneInfo() {

    }

    public PhoneInfo(String phoneNumber, String contactName, Long contactid, Long photoid, ContentResolver resolver, Context context) {
        this.phoneNumber = phoneNumber;
        this.contactName = contactName;
        this.contactid   = contactid;
        this.photoid     = photoid;
        getContactPhoto(photoid, resolver, context);
        firstLetter = getFirstLetter(contactName).charAt(0);
        isHead = false;

    }

    // 根据photoid获取图片Bitmap
    public Bitmap getContactPhoto(Long photoid, ContentResolver resolver, Context context) {
        //photoid大于0 表示联系人有头像 如果没有给此人设置头像则给他一个默认的
        if(photoid > 0 ) {
            Uri uri = ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI, contactid);
            InputStream input = ContactsContract.Contacts.openContactPhotoInputStream(resolver, uri);
            contactPhoto = BitmapFactory.decodeStream(input);
        }else {
            contactPhoto = BitmapFactory.decodeResource(context.getResources(), R.mipmap.error_photo);
        }
        return contactPhoto;
    }

    // 判断每个string的首字母

    /**
     * 取得给定汉字的首字母,即声母
     * @param chinese 给定的汉字
     * @return 给定汉字的声母
     */
    private String getFirstLetter(String chinese) {
        if (chinese == null || chinese.trim().length() == 0) {
            return "";
        }
        chinese = this.conversionStr(chinese, "GB2312", "ISO8859-1");

        if (chinese.length() > 1) { // 判断是不是汉字
            int li_SectorCode = (int) chinese.charAt(0); // 汉字区码
            int li_PositionCode = (int) chinese.charAt(1); // 汉字位码
            li_SectorCode = li_SectorCode - 160;
            li_PositionCode = li_PositionCode - 160;
            int li_SecPosCode = li_SectorCode * 100 + li_PositionCode; // 汉字区位码
            if (li_SecPosCode > 1600 && li_SecPosCode < 5590) {
                for (int i = 0; i < 23; i++) {
                    if (li_SecPosCode >= li_SecPosValue[i]
                            && li_SecPosCode < li_SecPosValue[i + 1]) {
                        chinese = lc_FirstLetter[i];
                        break;
                    }
                }
            } else { // 非汉字字符,如图形符号或ASCII码
                chinese = this.conversionStr(chinese, "ISO8859-1", "GB2312");
                chinese = chinese.substring(0, 1);
            }
        }

        return chinese;
    }

    /**
     * 字符串编码转换
     * @param str 要转换编码的字符串
     * @param charsetName 原来的编码
     * @param toCharsetName 转换后的编码
     * @return 经过编码转换后的字符串
     */
    private String conversionStr(String str, String charsetName,String toCharsetName) {
        try {
            str = new String(str.getBytes(charsetName), toCharsetName);
        } catch (UnsupportedEncodingException ex) {
            System.out.println("字符串编码转换异常:" + ex.getMessage());
        }
        return str;
    }

    /** 为一个List<PhoneInfo> 提供一个函数判断该元素是否一个字母索引的首字母 **/
    public static void tagIsHead (List<PhoneInfo> phoneInfos) {
        boolean[] isHead = new boolean[27];
        int index;
        // 先清除所有标志
        for (PhoneInfo info : phoneInfos) {
            info.isHead = false;
            index = info.firstLetter >= 'A' && info.firstLetter <= 'Z' ? info.firstLetter - 'A' : 26;

            if (!isHead[index]) {
                isHead[index] = true;
                info.isHead = true;
            }
        }
    }

    /** 一些列Setter函数 **/
    public void setPhoneNumber(String phoneNumber) {
        this.phoneNumber = phoneNumber;
    }

    public void setContactName(String contactName) {
        this.contactName = contactName;
    }
    public void setContactid(Long contactid) {
        this.contactid = contactid;
    }

    public void setPhotoid(Long photoid, ContentResolver resolver, Context context) {
        this.photoid = photoid;
        getContactPhoto(photoid, resolver, context);
    }

    public void setContactPhoto(Bitmap contactPhoto) {
        this.contactPhoto = contactPhoto;
    }

    public void setFirstLetter(char firstLetter) {
        this.firstLetter = firstLetter;
    }

    public void setIsHead(boolean isHead) {
        this.isHead = isHead;
    }

    /** 一些getter函数 **/
    public String getPhoneNumber() {
        return phoneNumber;
    }

    public String getContactName() {
        return contactName;
    }

    public Long getContactid() {
        return contactid;
    }

    public Long getPhotoid() {
        return photoid;
    }

    public Bitmap getContactPhoto() {
        return contactPhoto;
    }

    public char getFirstLetter() {
        return firstLetter;
    }

    public boolean isHead() {
        return isHead;
    }
}

6、每个Item的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="wrap_content"
    android:padding="15dp"
    >
    <TextView
        android:id="@+id/txtHeadLetter"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@color/grey21"
        android:textColor="@color/white"
        android:gravity="left|center_vertical"
        android:paddingLeft="10dp"
        android:visibility="gone"
        />

    <ImageView
        android:id="@+id/img_phonePhoto"
        android:layout_width="40dp"
        android:layout_height="40dp"
        android:layout_below="@id/txtHeadLetter"
        />

    <TextView
        android:id="@+id/txt_contactName"
        android:layout_width="match_parent"
        android:layout_height="20dp"
        android:layout_toRightOf="@id/img_phonePhoto"
        android:layout_marginLeft="10dp"
        android:gravity="center_vertical"
        android:layout_below="@id/txtHeadLetter"
        />

    <TextView
        android:id="@+id/txt_phoneNumber"
        android:layout_width="match_parent"
        android:layout_height="20dp"
        android:layout_toRightOf="@id/img_phonePhoto"
        android:layout_marginLeft="10dp"
        android:layout_below="@id/txt_contactName"
        android:gravity="center_vertical"
        />

</RelativeLayout>


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值