Android手机联系人快速索引(手机通讯录)

最近需要实现一个手机通讯录的快速索引功能。根据姓名首字母快速索引功能。下面是一个手机联系人快速索引的效果,总体来说代码不算难,拼音转换的地方略有复杂。下面上源码:源码中有注释。

下面是效果图:

MainActivity:

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.TextView;
/**
 * 这里是主布局
 * @author lxd
 *
 */
public class MainActivity extends Activity {
 private ListView lv_main;
 private FriendAdapter adapter;
 private List<Friend> data = new ArrayList<Friend>();
 private QuickIndexView qiv_main;
 private TextView tv_main_word;
 private Handler handler = new Handler(){
  public void handleMessage(android.os.Message msg) {
   //隐藏word
   tv_main_word.setVisibility(View.GONE);
  }
 };
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  lv_main = (ListView) findViewById(R.id.lv_main);
  qiv_main = (QuickIndexView) findViewById(R.id.qiv_main);
  tv_main_word = (TextView) findViewById(R.id.tv_main_word);
  //设置监听
  qiv_main.setOnIndexChangedListener(new QuickIndexView.OnIndexChangedListener() {
   @Override
   public void onIndexChanged(String word) {
    tv_main_word.setText(word);
    tv_main_word.setVisibility(View.VISIBLE);
    //handler.removeMessages(1);
    //移除未处理的消息
    handler.removeCallbacksAndMessages(null);
    //发延迟消息
    handler.sendEmptyMessageDelayed(1, 2000);
    //滑动listview
    //查找对应的item
    for(int i=0;i<data.size();i++) {
     String fWord = data.get(i).getPinyin().substring(0, 1);
     if(word.equals(fWord)) {
      lv_main.setSelection(i);
      return;
     }
    }
   }
   @Override
   public void onUp() {
    //tv_main_word.setVisibility(View.GONE);
   }
  });
  //显示列表
  adapter = new FriendAdapter();
  initData();
  lv_main.setAdapter(adapter);
  //lv_main.setSelection(5);
 }
 private void initData() {
  data.add(new Friend("张三"));
  data.add(new Friend("杨九"));
  data.add(new Friend("胡继群"));
  data.add(new Friend("刘畅"));
  data.add(new Friend("钟泽兴"));
  data.add(new Friend("尹革新"));
  data.add(new Friend("安传鑫"));
  data.add(new Friend("张骞壬"));
  data.add(new Friend("温松"));
  data.add(new Friend("李凤秋"));
  data.add(new Friend("刘甫"));
  data.add(new Friend("娄全超"));
  data.add(new Friend("张猛"));
  data.add(new Friend("王英杰"));
  data.add(new Friend("李振南"));
  data.add(new Friend("孙仁政"));
  data.add(new Friend("唐春雷"));
  data.add(new Friend("牛鹏伟"));
  data.add(new Friend("姜宇航"));
  data.add(new Friend("刘挺"));
  data.add(new Friend("张洪瑞"));
  data.add(new Friend("张建忠"));
  data.add(new Friend("侯亚帅"));
  data.add(new Friend("刘帅"));
  data.add(new Friend("乔竞飞"));
  data.add(new Friend("徐雨健"));
  data.add(new Friend("吴亮"));
  data.add(new Friend("王兆霖"));
  data.add(new Friend("阿三"));
  Collections.sort(data);
 }
 class FriendAdapter extends BaseAdapter {
  @Override
  public int getCount() {
   return data.size();
  }
  @Override
  public Object getItem(int position) {
   return data.get(position);
  }
  @Override
  public long getItemId(int position) {
   return 0;
  }
  @Override
  public View getView(int position, View convertView, ViewGroup parent) {
   ViewHolder holder = null;
   if(convertView==null) {
    holder = new ViewHolder();
    convertView = View.inflate(MainActivity.this, R.layout.item_main, null);
    holder.wordTV = (TextView) convertView.findViewById(R.id.tv_item_word);
    holder.nameTV = (TextView) convertView.findViewById(R.id.tv_item_name);
    convertView.setTag(holder);//***********?
   } else {
    holder = (ViewHolder) convertView.getTag();
   }
   Friend friend = data.get(position);
   String word = friend.getPinyin().substring(0, 1);
   holder.wordTV.setText(word);
   holder.nameTV.setText(friend.getName());
   //下标为0的显示
   if(position==0) {
    holder.wordTV.setVisibility(View.VISIBLE);
   } else {
    //取出上一个friend, 并得到的第一个word
    String preWord = data.get(position-1).getPinyin().substring(0, 1);
    //判断是否于当前行的word是否相同
     //如果相同, 隐藏
    if(word.equals(preWord)) {
     holder.wordTV.setVisibility(View.GONE);
    } else {
     //如果不同, 显示
     holder.wordTV.setVisibility(View.VISIBLE);
    }
   }
   return convertView;
  }
  class ViewHolder {
   public TextView wordTV;
   public TextView nameTV;
  }
 }
}

主布局:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:tools="http://schemas.android.com/tools"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 tools:context="${relativePackage}.${activityClass}" >
 <ListView
  android:id="@+id/lv_main"
  android:layout_width="match_parent"
  android:layout_height="match_parent" >
 </ListView>
 <!-- com.atguigu.quickindex.QuickIndexView -->
 <com.atguigu.quickindex.QuickIndexView
  android:id="@+id/qiv_main"
  android:layout_width="40dp"
  android:layout_height="match_parent"
  android:layout_alignParentRight="true"
  android:background="#ffffff" >
 </com.atguigu.quickindex.QuickIndexView>
 <TextView
  android:id="@+id/tv_main_word"
  android:layout_width="100dp"
  android:layout_height="100dp"
  android:layout_centerHorizontal="true"
  android:layout_centerVertical="true"
  android:background="#66666666"
  android:text="A"
  android:textSize="40sp"
  android:gravity="center"
  android:visibility="gone"/>
</RelativeLayout>

Item:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:orientation="vertical" >
 <TextView
  android:id="@+id/tv_item_word"
  android:layout_width="fill_parent"
  android:layout_height="wrap_content"
  android:text="A"
  android:background="#66666666"
  android:textSize="18sp"
  android:padding="5dp"/>
 <TextView
  android:id="@+id/tv_item_name"
  android:layout_width="fill_parent"
  android:layout_height="wrap_content"
  android:text="某人"
  android:textSize="18sp"
  android:padding="5dp"/>
</LinearLayout>

自定义View:

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
/**
 * 这里是自定义View
 * @author lxd
 *
 */
public class QuickIndexView extends View {
 private float itemWidth;
 private float itemHeight;
 // private float wordWidth;
 // private float wordHeight;
 private String[] indexArr = { "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 Paint paint;
 public QuickIndexView(Context context, AttributeSet attrs) {
  super(context, attrs);
  paint = new Paint();
  paint.setColor(Color.WHITE);
  paint.setTextSize(16);
  paint.setAntiAlias(true);
 }
 @Override
 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  super.onMeasure(widthMeasureSpec, heightMeasureSpec);
  itemWidth = this.getMeasuredWidth();
  itemHeight = this.getMeasuredHeight() / 26f;
 }
 @Override
 protected void onDraw(Canvas canvas) {
  //当每次触发重绘的时候,就把26个字母循环一遍
  for (int i = 0; i < indexArr.length; i++) {
   String word = indexArr[i];
   // 设置文字的颜色
   if (i == touchIndex) {
    //这里设置被点击的字母变化:颜色变灰色、字体变25sp
    paint.setColor(Color.GRAY);
    paint.setTextSize(25);
   } else {
    //其他没被点击的字母,保持原有状态:设置颜色、字体大小为18sp
    paint.setColor(Color.BLACK);
    paint.setTextSize(18);
   }
   // 得到word的宽高
   Rect bounds = new Rect();
   paint.getTextBounds(word, 0, word.length(), bounds);
   //得到字体的宽
   int wordWidth = bounds.width();
   //得到字体的高
   int wordHeight = bounds.height();
   // 计算word的左上角的坐标:字母所在的X坐标、Y坐标
   float x = itemWidth / 2 - wordWidth / 2;
   float y = itemHeight / 2 + wordHeight / 2 + i * itemHeight;
   // 绘制word
   canvas.drawText(word, x, y, paint);
  }
 }
 // ///////////////////////////////////////////////////////////////////////
 private int touchIndex = -1;// 触摸的字母的下标
 @Override
 public boolean onTouchEvent(MotionEvent event) {
  // 得到事件坐标
  float eventY = event.getY();
  switch (event.getAction()) {
  case MotionEvent.ACTION_DOWN:
  case MotionEvent.ACTION_MOVE:
   // 计算下标
   int index = (int) (eventY / itemHeight);
   if (index > 25) {
    index = 25;
   }
   if (index < 0) {
    index = 0;
   }
   // 如果下标有改变, 强制重绘
   if (index != touchIndex) {
    // 更新touchIndex
    touchIndex = index;
    // 强制重绘
    invalidate();
    // 通知Activity更新TextView
    if (onIndexChangedListener != null) {
     onIndexChangedListener.onIndexChanged(indexArr[index]);
    }
   }
   break;
  case MotionEvent.ACTION_UP:
   touchIndex = -1;
   // 强制重绘
   invalidate();
   // 通知Activity更新TextView
   if (onIndexChangedListener != null) {
    onIndexChangedListener.onUp();
   }
   break;
  default:
   break;
  }
  return true;// 所有的事件都由当前视图消费
 }
 private OnIndexChangedListener onIndexChangedListener;
 /*
  * 设置监听对象的方法 这个方法一般是Activity调用
  */
 public void setOnIndexChangedListener(
   OnIndexChangedListener onIndexChangedListener) {
  this.onIndexChangedListener = onIndexChangedListener;
 }
 interface OnIndexChangedListener {
  // 当操作的下标改变时自动调用
  public void onIndexChanged(String word);
  // 当up时调用
  public void onUp();
 }
}

联系人类:

/**
 * 联系人类
 * @author lxd
 *
 */
public class Friend implements Comparable<Friend> {
 private String name;
 private String pinyin;
 public Friend(String name) {
  super();
  this.name = name;
  pinyin = PinYinUtils.getPinYin(name);
 }
 public String getName() {
  return name;
 }
 public void setName(String name) {
  this.name = name;
 }
 public String getPinyin() {
  return pinyin;
 }
 public void setPinyin(String pinyin) {
  this.pinyin = pinyin;
 }
 @Override
 public String toString() {
  return "Friend [name=" + name + ", pinyin=" + pinyin + "]";
 }
 @Override
 public int compareTo(Friend another) {
  return this.pinyin.compareTo(another.getPinyin());
 }
}

工具类:用于将汉字转换为拼音

/**
 * 将汉字转换为拼音
 * @author lxd
 *
 */
public class PinYinUtils {
 /**
  * 得到指定汉字的拼音
  * 注意:不应该被频繁调用,它消耗一定内存
  * @param hanzi
  * @return
  */
 public static String getPinYin(String hanzi){
  String pinyin = "";
  HanyuPinyinOutputFormat format = new HanyuPinyinOutputFormat();//控制转换是否大小写,是否带音标
  format.setCaseType(HanyuPinyinCaseType.UPPERCASE);//大写
  format.setToneType(HanyuPinyinToneType.WITHOUT_TONE);
  //由于不能直接对多个汉字转换,只能对单个汉字转换
  char[] arr = hanzi.toCharArray();
  for (int i = 0; i < arr.length; i++) {
   if(Character.isWhitespace(arr[i]))continue;//如果是空格,则不处理,进行下次遍历
   //汉字是2个字节存储,肯定大于127,所以大于127就可以当为汉字转换
   if(arr[i]>127){
    try {
     //由于多音字的存在,单 dan shan
     String[] pinyinArr = PinyinHelper.toHanyuPinyinStringArray(arr[i], format);
     if(pinyinArr!=null){
      pinyin += pinyinArr[0];
     }else {
      pinyin += arr[i];
     }
    } catch (BadHanyuPinyinOutputFormatCombination e) {
     e.printStackTrace();
     //不是正确的汉字
     pinyin += arr[i];
    }
   }else {
    //不是汉字,
    pinyin += arr[i];
   }
  }
  return pinyin;
 }
}

以上代码是关于Android手机联系人快速索引(手机通讯录)的全部叙述,希望大家喜欢。

(0)

相关推荐

  • android仿微信通讯录搜索示例(匹配拼音,字母,索引位置)

    前言: 仿微信通讯录搜索功能,通过汉字或拼音首字母找到匹配的联系人并显示匹配的位置 一:先看效果图 字母索引 搜索匹配 二:功能分析 1:汉字转拼音 通讯录汉字转拼音(首个字符当考虑姓氏多音字), 现在转换拼音常见的有pinyin4j和tinypinyin, pinyin4j的功能强大,包含声调多音字,tinypinyin执行快占用内存少, 如果只是简单匹配通讯录,建议使用tinypinyin,用法也很简单这里不详细介绍 拼音类 public class CNPinyin <T extends

  • android 左右滑动+索引图标实现方法与代码

    使用Gallery和ImageView实现android左右滑动+索引图标效果. 首先自定义Gallery实现一次只能滑动一个页面 复制代码 代码如下: public class MGalleryView extends Gallery{ public MGalleryView(Context context, AttributeSet attrs) { super(context, attrs); } //一次只能滑动一张图片注:一张图充满全屏 @Override public boolean

  • Android自定义View实现通讯录字母索引(仿微信通讯录)

    一.效果:我们看到很多软件的通讯录在右侧都有一个字母索引功能,像微信,小米通讯录,QQ,还有美团选择地区等等.这里我截了一张美团选择城市的图片来看看: 我们今天就来实现图片中右侧模块的索引功能,包括触摸显示以选中的索引字母.这里我的UI界面主要是参照微信的界面来实现,所以各位也可以对照微信来看看效果,什么都不说了,只有效果图最具有说服力! 二.分析: 我们看到这样的效果我们心理都回去琢磨,他是如何实现的: 首先,它肯定是通过自定义 View 来实现的,因为 Android 没有提供类似这样的控件

  • Android通用索引栏实现代码

    偶尔看到之前写过的代码,感觉好多东西几乎在很多项目中都要用到,虽然每个项目的需求和设计都不同,不过实现的效果都是一样的,可能只是数据格式和一些颜色等的细微差距.但是有的时候因为一个小改变,就要去重复的修改代码,麻烦不说,也容易导致新的问题和BUG. 就拿忽然想到的索引栏来说,几乎写过的项目中都用到了,比如城市选择.联系人等等.这些地方全都需要用到索引栏,但是用法都是一样的.翻看了几处之前写过的代码,发现每次用到索引栏,都要重新去写方法来处理数据或者对数据的索引进行提取这些,做法也都大同小异.于是

  • Android手机联系人带字母索引的快速查找

    喜欢另辟蹊径的我,在这里废话不多说了,直接上代码和图片了. 效果图如下: 第一步:MainActivity的代码如下: package net.loonggg.test; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.TreeSet; import android.os.Bundle; import and

  • Android 实现带字母索引的侧边栏功能

    之前已经用自定义View做出如下这样一个效果了 这两天需要重新拿来使用,发现效果虽然做出来了,不过思路不太对,就重新参考写了一个,用法也更为简单了 首要的自然是需要继承View绘制出侧边栏,并向外提供一个监听字母索引变化的方法 /** * 作者:叶应是叶 * 时间:2017/8/20 11:38 * 描述: */ public class LetterIndexView extends View { public interface OnTouchingLetterChangedListener

  • Android ItemDecoration 实现分组索引列表的示例代码

    本文介绍了Android ItemDecoration 实现分组索引列表的示例代码,分享给大家.具体如下: 先来看看效果: 我们要实现的效果主要涉及三个部分: 分组 GroupHeader 分割线 SideBar 前两个部分涉及到一个ItemDecoration类,也是我们接下来的重点,该类是RecyclerView的一个抽象静态内部类,主要作用就是给RecyclerView的ItemView绘制额外的装饰效果,例如给RecyclerView添加分割线. 使用ItemDecoration时需要继

  • android将搜索引擎设置为中国雅虎无法搜索问题解决方法

    该问题是由于yahoo的搜索接口改变导致,请修改 Donottranslate-all_search_engines.xml (x:\6575gb2\v2.12\alps\mediatek\source\frameworks\banyan\res\res\values)41753 8/11/2011 中的<string-array name="yahoo_cn" translatable="false">的定义为 复制代码 代码如下: <strin

  • Android手机联系人快速索引(手机通讯录)

    最近需要实现一个手机通讯录的快速索引功能.根据姓名首字母快速索引功能.下面是一个手机联系人快速索引的效果,总体来说代码不算难,拼音转换的地方略有复杂.下面上源码:源码中有注释. 下面是效果图: MainActivity: import java.util.ArrayList; import java.util.Collections; import java.util.List; import android.app.Activity; import android.os.Bundle; imp

  • Android ContentProvider获取手机联系人实例

    在做项目的时候,因为要用到我们自动获取联系人的姓名和电话,就想到了ContentProvider分享数据的功能,这样做既节省了时间,也减少了我们输入错误号码的几率,所以,想在这里把小demo分享给大家,方便以后要用的时候可以看看 我们先看下获取所有联系人的方式,把所有联系人展示在listView上 public void getLinkMan(View view){ //获取联系人 Uri uri=Uri.parse("content://com.android.contacts/raw_con

  • android如何获取手机联系人的数据库示例代码

    很多人在做手机联系人的apk时会遇到,如何获取手机联系人数据库的问题,在这里我就简单的将代码写一下 package com.example.song.lx_day14_contacts; import android.content.ContentResolver; import android.database.Cursor; import android.net.Uri; import android.os.Bundle; import android.support.v7.app.AppC

  • Android Loader的使用以及手机通讯录的获取方法

    Android的主线程中执行长时间操作,导致界面无响应,会引起ANR.如果需要执行较长时间的操作,一般会在另一个线程处理,然后将数据转交给主线程进行显示,Android本身为我们提供了一些机制处理这种情况,今天就来看看Loader.Loader主要用来在Activity和Fragment中异步加载数据,使用也非常简单. Loader的初始化非常简单,Activity提供了获取LoaderManager的接口,之后调用LoaderManager的initLoader即可.initLoader接受三

  • Android编程实现读取手机联系人、拨号、发送短信及长按菜单操作方法实例小结

    本文实例讲述了Android编程实现读取手机联系人.拨号.发送短信及长按菜单操作方法.分享给大家供大家参考,具体如下: 1.Andrid项目结构图↓主要操作图中红色方框内的文件. 2.首先布局代码如下 a, main.xml 程序运行的主界面,主要用ListView列表控件展示手机联系人 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://s

  • Android ContentProvider实现获取手机联系人功能

    在之前项目中有用到关于获取手机联系人的部分,闲置就想和大家分享一下,话不多说,上代码: java部分: package com.example.content; import android.content.ContentResolver; import android.database.Cursor; import android.net.Uri; import android.support.v7.app.AppCompatActivity; import android.os.Bundle

  • android利用ContentResolver访问者获取手机联系人信息

    利用ContentResolver内容访问者,获取手机联系人信息我做了两种不同的做法.第一种,直接获取所有手机联系人信息,展示在ListView中.第二种,通过Butten按钮跳转到系统的手机联系人界面,单个获取手机联系人信息,展示在ListView中,结果如下: 第一种: 第二种: 第一种:直接获取所有手机联系人信息 首先需要在AndroidManifest.xml文件中添加权限: <uses-permission android:name="android.permission.REA

  • Android使用AsyncQueryHandler实现获取手机联系人功能

    利用AsyncQueryHandler能异步任务获取手机联系人,增加用户体验,使用起来也很方便.不多说,上干货. 布局文件main.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.a

  • 浅谈Android手机联系人开发之增删查改功能

    最近在做手机联系人的功能模块的时候,遇到了很多的坑,在网上搜索的有一些所谓的最全的手机联系人开发的介绍还存在一些bug,所以我把我最近的项目心得和方法写下来,既能帮助大家减少了解android开发手机联系人的门槛,好,废话少说,接下来直奔主题. 一.深入浅出手机联系人的前奏(小米手机的data表跟模拟器的data表不一样) 1.手机联系人主要是对contacts2.db数据库表的操纵,这个数据库中有三个表是比较重要的,分别是data,raw_contacts,mimetyps这三个表.在下面的增

  • Android ContentProvider查看/读取手机联系人实例

    看到某些App里面有读取联系人的功能,然后自己尝试了一下.发现这个挺简单的.然后自己就做了一个demo给大家,希望借这个demo可以让大家学习一下怎么实现读取手机联系人. 这里我用了两种方法去读取:第一张图片是跳转到系统自带的联系人界面,第二种就是直接去读取让后绑上来显示在主页面.话不多说直接上代码. 记得在AndroidManifest.xml 记得加入这两句,不然就读取不到联系人. <uses-permission android:name="android.permission.RE

随机推荐