Android之实现系统联系人软件的分组和字母提示效果

Android系统联系人全特效实现(上),分组导航和挤压动画 布局文件很简单,里面放入了一个 ListView,用于展示联系人信息。另外还在头部放了一个 LinearLayout,里面包含了一个 TextView,它的作用是在界面头部始终显示一个当前分组。 阅读详情
联系人分章节显示以及ListView快速滑动显示联系人首字母例子,查阅网上很多这样的例子后,发现普遍是从系统源码里面抽取的,而且普遍比较复杂,这里做了精简,扩展性较强,移植起来非常方便。


1.FastContactSearchDemoActivity.java

[javascript] view plain copy print ?
  1. package com.zhf.FastContactSearchDemo; 
  2.  
  3. import java.util.ArrayList; 
  4. import java.util.Collections; 
  5. import java.util.HashMap; 
  6. import java.util.List; 
  7. import java.util.Set; 
  8. import java.util.regex.Pattern; 
  9. import android.app.Activity; 
  10. import android.content.AsyncQueryHandler; 
  11. import android.content.ContentResolver; 
  12. import android.content.ContentValues; 
  13. import android.content.Context; 
  14. import android.database.Cursor; 
  15. import android.net.Uri; 
  16. import android.os.Bundle; 
  17. import android.view.LayoutInflater; 
  18. import android.view.View; 
  19. import android.view.ViewGroup; 
  20. import android.widget.BaseAdapter; 
  21. import android.widget.ListView; 
  22. import android.widget.SectionIndexer; 
  23. import android.widget.TextView; 
  24.  
  25. /**
  26. * 联系人分章节显示以及ListView快速滑动显示联系人首字母例子
  27. * 本例来自http://blog.youkuaiyun.com/luck_apple/article/details/6741860
  28. * 查阅网上很多这样的例子后,发现普遍是从系统源码里面抽取的,而且普遍比较复杂,这里做了精简,扩展性较强,移植起来非常方便。
  29. * @author hiphonezhu@sina.com
  30. *
  31. */ 
  32. public class FastContactSearchDemoActivityextends Activity { 
  33.     private BaseAdapter adapter; 
  34.     private ListView personList; 
  35.     private AsyncQueryHandler asyncQuery; 
  36.     private staticfinal String NAME ="name", NUMBER ="number", 
  37.             SORT_KEY = "sort_key"; 
  38.  
  39.     @Override 
  40.     public void onCreate(Bundle savedInstanceState) { 
  41.         super.onCreate(savedInstanceState); 
  42.         setContentView(R.layout.main); 
  43.         personList = (ListView) findViewById(R.id.listView); 
  44.         asyncQuery = new MyAsyncQueryHandler(getContentResolver()); 
  45.     } 
  46.  
  47.     @Override 
  48.     protected void onResume() { 
  49.         super.onResume(); 
  50.         Uri uri = Uri.parse("content://com.android.contacts/data/phones"); // 联系人的Uri 
  51.         String[] projection = { "_id","display_name","data1","sort_key" };// 查询的列 
  52.         asyncQuery.startQuery(0, null, uri, projection,null,null, 
  53.                 "sort_key COLLATE LOCALIZED asc");// 按照sort_key升序查询 
  54.     } 
  55.  
  56.     /**
  57.      * 数据库异步查询类AsyncQueryHandler
  58.      *
  59.      * @author administrator
  60.      *
  61.      */ 
  62.     private class MyAsyncQueryHandlerextends AsyncQueryHandler { 
  63.  
  64.         public MyAsyncQueryHandler(ContentResolver cr) { 
  65.             super(cr); 
  66.  
  67.         } 
  68.  
  69.         /**
  70.          * 查询结束的回调函数
  71.          */ 
  72.         @Override 
  73.         protected void onQueryComplete(int token, Object cookie, Cursor cursor) { 
  74.             if (cursor != null && cursor.getCount() > 0) { 
  75.                 List<ContentValues> list = new ArrayList<ContentValues>(); 
  76.                 cursor.moveToFirst(); 
  77.                 for (int i = 0; i < cursor.getCount(); i++) { 
  78.                     ContentValues cv = new ContentValues(); 
  79.                     cursor.moveToPosition(i); 
  80.                     String name = cursor.getString(1); 
  81.                     String number = cursor.getString(2); 
  82.                     String sortKey = cursor.getString(3); 
  83.  
  84.                     if (number.startsWith("+86")) {// 去除多余的中国地区号码标志,对这个程序没有影响。 
  85.                         cv.put(NAME, name); 
  86.                         cv.put(NUMBER, number.substring(3)); 
  87.                         cv.put(SORT_KEY, sortKey); 
  88.                     } else { 
  89.                         cv.put(NAME, name); 
  90.                         cv.put(NUMBER, number); 
  91.                         cv.put(SORT_KEY, sortKey); 
  92.                     } 
  93.                     list.add(cv); 
  94.                 } 
  95.                 if (list.size() > 0) { 
  96.                     setAdapter(list); 
  97.                 } 
  98.             } 
  99.         } 
  100.  
  101.     } 
  102.  
  103.     private void setAdapter(List<ContentValues> list) { 
  104.         adapter = new ListAdapter(this, list); 
  105.         personList.setAdapter(adapter); 
  106.  
  107.     } 
  108.  
  109.     private staticclass ViewHolder { 
  110.         TextView alpha; 
  111.         TextView name; 
  112.         TextView number; 
  113.     } 
  114.  
  115.     /**
  116.      * 其他项目使用时,只需要传进来一个有序的list即可
  117.      */ 
  118.     private class ListAdapterextends BaseAdapterimplements SectionIndexer { 
  119.         private LayoutInflater inflater; 
  120.         private List<ContentValues> list; 
  121.         private HashMap<String, Integer> alphaIndexer;//保存每个索引在list中的位置【#-0,A-4,B-10】 
  122.         private String[] sections;//每个分组的索引表【A,B,C,F...】 
  123.  
  124.         public ListAdapter(Context context, List<ContentValues> list) { 
  125.             this.inflater = LayoutInflater.from(context); 
  126.             this.list = list; // 该list是已经排序过的集合,有些项目中的数据必须要自己进行排序。 
  127.             this.alphaIndexer =new HashMap<String, Integer>(); 
  128.  
  129.             for (int i =0; i <list.size(); i++) { 
  130.                 String name = getAlpha(list.get(i).getAsString(SORT_KEY)); 
  131.                 if(!alphaIndexer.containsKey(name)){//只记录在list中首次出现的位置 
  132.                     alphaIndexer.put(name, i); 
  133.                 } 
  134.             } 
  135.             Set<String> sectionLetters = alphaIndexer.keySet(); 
  136.             ArrayList<String> sectionList = new ArrayList<String>( 
  137.                     sectionLetters); 
  138.             Collections.sort(sectionList); 
  139.             sections = new String[sectionList.size()]; 
  140.             sectionList.toArray(sections); 
  141.         } 
  142.  
  143.         @Override 
  144.         public int getCount() { 
  145.             return list.size(); 
  146.         } 
  147.  
  148.         @Override 
  149.         public Object getItem(int position) { 
  150.             return list.get(position); 
  151.         } 
  152.  
  153.         @Override 
  154.         public long getItemId(int position) { 
  155.             return position; 
  156.         } 
  157.  
  158.         @Override 
  159.         public View getView(int position, View convertView, ViewGroup parent) { 
  160.             ViewHolder holder; 
  161.  
  162.             if (convertView == null) { 
  163.                 convertView = inflater.inflate(R.layout.list_item,null); 
  164.                 holder = new ViewHolder(); 
  165.                 holder.alpha = (TextView) convertView.findViewById(R.id.alpha); 
  166.                 holder.name = (TextView) convertView.findViewById(R.id.name); 
  167.                 holder.number = (TextView) convertView 
  168.                         .findViewById(R.id.number); 
  169.                 convertView.setTag(holder); 
  170.             } else { 
  171.                 holder = (ViewHolder) convertView.getTag(); 
  172.             } 
  173.             ContentValues cv = list.get(position); 
  174.             String name = cv.getAsString(NAME); 
  175.             String number = cv.getAsString(NUMBER); 
  176.             holder.name.setText(name); 
  177.             holder.number.setText(number); 
  178.  
  179.             // 当前联系人的sortKey 
  180.             String currentStr = getAlpha(list.get(position).getAsString( 
  181.                     SORT_KEY)); 
  182.             // 上一个联系人的sortKey 
  183.             String previewStr = (position - 1) >= 0 ? getAlpha(list.get( 
  184.                     position - 1).getAsString(SORT_KEY)) : " "; 
  185.             /**
  186.              * 判断显示#、A-Z的TextView隐藏与可见
  187.              */ 
  188.             if (!previewStr.equals(currentStr)) {// 当前联系人的sortKey!=上一个联系人的sortKey,说明当前联系人是新组。 
  189.                 holder.alpha.setVisibility(View.VISIBLE); 
  190.                 holder.alpha.setText(currentStr); 
  191.             } else { 
  192.                 holder.alpha.setVisibility(View.GONE); 
  193.             } 
  194.             return convertView; 
  195.         } 
  196.  
  197.         /*
  198.          * 此方法根据联系人的首字母返回在list中的位置
  199.          */ 
  200.         @Override 
  201.         public int getPositionForSection(int section) { 
  202.             String later = sections[section]; 
  203.             return alphaIndexer.get(later); 
  204.         } 
  205.  
  206.         /*
  207.          * 本例中可以不考虑这个方法
  208.          */ 
  209.         @Override 
  210.         public int getSectionForPosition(int position) { 
  211.             String key = getAlpha(list.get(position).getAsString(SORT_KEY)); 
  212.             for (int i = 0; i < sections.length; i++) { 
  213.                 if (sections[i].equals(key)) { 
  214.                     return i; 
  215.                 } 
  216.             } 
  217.             return 0; 
  218.         } 
  219.  
  220.         @Override 
  221.         public Object[] getSections() { 
  222.             return sections; 
  223.         } 
  224.     } 
  225.  
  226.     /**
  227.      * 提取英文的首字母,非英文字母用#代替
  228.      *
  229.      * @param str
  230.      * @return
  231.      */ 
  232.     private String getAlpha(String str) { 
  233.         if (str == null) { 
  234.             return "#"; 
  235.         } 
  236.  
  237.         if (str.trim().length() == 0) { 
  238.             return "#"; 
  239.         } 
  240.  
  241.         char c = str.trim().substring(0, 1).charAt(0); 
  242.         // 正则表达式,判断首字母是否是英文字母 
  243.         Pattern pattern = Pattern.compile("^[A-Za-z]+{1}quot;); 
  244.         if (pattern.matcher(c + "").matches()) { 
  245.             return (c + "").toUpperCase(); // 大写输出 
  246.         } else { 
  247.             return "#"; 
  248.         } 
  249.     } 
  250. } 

2.布局文件

2.1.main.xml

  1. <?xmlversion="1.0"encoding="utf-8"?> 
  2. <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android" 
  3.     android:layout_width="fill_parent" 
  4.     android:layout_height="fill_parent" 
  5.     android:orientation="vertical"> 
  6.  
  7.     <ListView 
  8.         android:id="@+id/listView" 
  9.         android:layout_width="fill_parent" 
  10.         android:layout_height="fill_parent" 
  11.         android:fastScrollEnabled="true"/> 
  12.  
  13. </LinearLayout> 

2.2.list_item.xml

  1. <?xmlversion="1.0"encoding="utf-8"?> 
  2. <RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/android" 
  3.     android:layout_width="match_parent" 
  4.     android:layout_height="match_parent"> 
  5.      
  6.     <!-- 首字母 --> 
  7.     <TextView 
  8.         android:id="@+id/alpha" 
  9.         android:layout_width="fill_parent" 
  10.         android:layout_height="wrap_content" 
  11.         android:background="#333333" 
  12.         android:paddingLeft="10dip" 
  13.         android:textColor="#FFFFFF" 
  14.         android:visibility="gone"/> 
  15.      
  16.     <!-- 联系人信息 --> 
  17.     <ImageView 
  18.         android:id="@+id/imageView" 
  19.         android:layout_width="wrap_content" 
  20.         android:layout_height="wrap_content" 
  21.         android:layout_alignParentLeft="true" 
  22.         android:layout_below="@id/alpha" 
  23.         android:src="@drawable/ic_launcher"/> 
  24.  
  25.     <TextView 
  26.         android:id="@+id/name" 
  27.         android:layout_width="wrap_content" 
  28.         android:layout_height="wrap_content" 
  29.         android:layout_alignTop="@id/imageView" 
  30.         android:layout_marginLeft="2.0dip" 
  31.         android:layout_marginRight="5.0dip" 
  32.         android:layout_marginTop="6.0dip" 
  33.         android:layout_toRightOf="@id/imageView" 
  34.         android:singleLine="true" 
  35.         android:textAppearance="?android:textAppearanceMedium"/> 
  36.  
  37.     <TextView 
  38.         android:id="@+id/number" 
  39.         android:layout_width="wrap_content" 
  40.         android:layout_height="wrap_content" 
  41.         android:layout_alignLeft="@id/name" 
  42.         android:layout_alignWithParentIfMissing="true" 
  43.         android:layout_below="@id/name" 
  44.         android:ellipsize="marquee" 
  45.         android:singleLine="true" 
  46.         android:textAppearance="?android:textAppearanceSmall"/> 
  47.  
  48. </RelativeLayout> 

3.效果图


Android之联系人A~Z快速索引效果 说到android的联系人的快速索引,很快就能想到系统自带的快速索引效果,而且现在很多主流的应用都有用到,如QQ的通讯录,微信的通讯录等等。 要想实现快速索引的效果,我们先来理下其实现原理: 首先,我们需要定义一个自定义的控件,得到控件(自定义控件SlideBar)的总高度与宽度,通过SlideBar控件的总高度算出从A~Z(一般最后都有个#)每个字符的需要的高度,再通过循环偏移单个字符高度来 阅读详情

相关推荐

android通讯录分组管理

这是类似于QQ分组的一个android通讯录分组管理,并点击个人可以编写该人信息,还可以搜索好友,是个很不错的例子

用Android实现联系人按字母检索,GitHub - doubijuan/ContactsDome: Android 使用ListView的A-Z字母排序功能实现联系人模块,主要学习了ListVie...

ContactsDomeAndroid 使用ListView的A-Z字母排序功能实现联系人模块,主要学习了ListView的A-Z字母排序功能以及根据输入框的输入值改变来过滤搜索结果,如果输入框里面的值为空,更新为原来的列表,否则为过滤数据列表,包括汉字转成拼音的功能先来看一下最终效果图:现在我们来看下项目结构图其实很多都是和上一篇文章一样的,我在这里就不多说啦,不是很明白的地方,可以看一下上一篇...

weixin_39705850的博客 2819

Android-仿微信通讯录的实现联系人按字母分组显示右侧添加快速索引条

在APP中,只要有联系人,都肯定有通讯录页面,而且所有的通讯录以页面都很相似,一个列表,列表中的人员按字母排列,而且按字母分组显示,且右侧有快速索引。

python实现字母索引通讯录_Android 仿微信通讯录功能+字母索引+好友列表

一、效果图展示a.gif二、功能特点1.好友排序:按照拼音顺序对好友进行排序,兼容英文数字符号等2.字母索引:右侧字母导航条,既可拖动也可点击,联动ListView滑动三、实现接下来就让我们一步步显示这个效果吧。1.右侧字母索引的导航条这个我们可以在网上找到很多类似的,你大可找一个自己喜欢的甚至自己写一个出来,这里我在网上找了一个带波浪效果的,看起来比较炫酷一点吧。然后我把它导入到了我们项目中并修...

weixin_39566387的博客 367

Android通讯录分组联系人更新

Android 调用系统通讯录 新建分组,添加分组数据 删除分组数据

【Android 仿微信通讯录 导航分组列表-上】使用ItemDecoration为RecyclerView打造带悬停头部的分组列表

【Android 仿微信通讯录 导航分组列表-上】使用ItemDecoration为RecyclerView打造带悬停头部的分组列表 代码: 博客:http://blog.youkuaiyun.com/zxt0601/article/details/52355199

android 通讯录界面设计带字母,android仿微信联系人索引列表功能

前言因为自己在做的一个小软件里面需要用到从A-Z排序的ListView,所以自然而然的想到了微信的联系人,我想要的就是那样的效果。本来没打算自己去写,想要第三方写好的东西,搜了几个之后发现有的太复杂了,有的简单是简单,但是不符合我的要求,所以我就来个整合,把复杂性和简单性合二为一。实现先来看效果图吧:要点分析要实现这样的效果需要考虑下面的几个问题:右边字母栏的绘制点击效果的实现汉字按A-Z的排序问...

weixin_31613423的博客 999

Android仿微信通讯录打造带悬停头部的分组列表(上)

主要介绍了Android 仿微信通讯录导航分组列表,使用ItemDecoration为RecyclerView打造带悬停头部的分组列表,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

模仿通讯录按字母分类显示,汉字,英文自动按英文字母分类显示,滑动时用气泡显示最上面的汉字首字母提示,右侧字母栏点击快速定位

废话不多说,先上图。   本Demo实现了如下功能: 1.根据汉字首字母,自动按英文字母分类显示。 2.滑动时,泡泡显示最上面的汉字首字母提示。 3.右侧字母栏点击快速定位,方便多数据的查找定位。 不足之处: 1.汉字转化得到拼音首字母的时候,我用到了一个pinyin4j-2.5.0.jar包,多音字和某些特殊汉字翻译不准确,如:我发现厦门,它会翻译成shamen,结果首字母变成了s

nicholas6lee的专栏 1万+

保姆级教程:用OpenCV和MediaPipe在Python里实现实时手势识别(附完整代码)

本文提供了一份详细的Python教程,教你如何使用OpenCV和MediaPipe实现实时手势识别系统。从环境配置、手部关键点检测到手势分类算法,逐步讲解如何构建高精度手势识别应用,适用于智能家居控制、PPT操作等场景。教程包含完整代码示例和性能优化技巧,特别适合计算机视觉初学者和开发者实践。

weixin_28677005的博客 331

KV260-从开箱到人脸识别(小白入门)

波特率选择115200,数据为8位,停止位1位,无奇偶校验,点击链接即可完成通讯。空白的盘格式化之后及进行挂载,这时会被我们的操作系统接手管理,这时就具有了操作系统的属性,复制文件就是在操作系统下的文件系统基础上进行的操作,这个过程是相对的地址进行操作,因此,复制文件是在操作系统环境下完成的更高级的操作模式。空白的盘相当于一整块空白的存储单元,因为没有格式化也不具有文件系统的属性,只有当外部的硬件或者软件写进空白的区域,这种方式是对绝对物理地址进行的操作,因此,烧录文件是独立于操作系统的更低级的写入方式。

qq_53252845的博客 3815

Android通讯录之分组联系人

Android系统联系人信息通过 ContentProvider提供给我们使用,具体请参看contacts2.db 一、获取所有的分组信息 /** * 获取所有的 联系人分组信息 * * @return */ public List getAllGroupInfo() { List groupList = new ArrayList(); Cursor cu

Ricky 8090

Android 车载应用开发与优化(1) - CarLauncher 核心功能与动态集成探秘

本文深入探讨了Android车载应用开发中CarLauncher的核心功能与实现原理。作为车载系统的“脸面”,CarLauncher不仅提供应用入口,更通过动态集成技术将地图、音乐等关键信息嵌入桌面,以保障驾驶安全与体验。文章详细解析了其源码结构、权限配置、应用启动机制以及基于Activity嵌入的动态集成黑魔法,为开发者提供了从基础认识到高级优化的完整指南。

weixin_29239279的博客 284

Android系统联系人全特效实现(下),字母表快速滚动

有任何问题,欢迎广大网友一起来交流,分享高阶Android学习视频资料和面试资料包~偷偷说一句:群里高手如云,欢迎大家加群和大佬们一起交流讨论啊!《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门即可获取!有任何问题,欢迎广大网友一起来交流,分享高阶Android学习视频资料和面试资料包~偷偷说一句:群里高手如云,欢迎大家加群和大佬们一起交流讨论啊![外链图片转存中…(img-2mceB3Pm-1712237605758)]

2401_84123026的博客 1038

非华为电脑与MatePad Pro多屏协同实战:从安装管家到攻克连接难题

本文详细介绍了在非华为电脑上安装华为电脑管家并实现与MatePad Pro多屏协同的完整指南。从安装步骤、常见连接失败解决方案到华为账号绑定技巧,提供了实用的操作方法和硬件优化建议,帮助用户攻克连接难题,提升多屏协同的稳定性和流畅度。

weixin_30263073的博客 234

免疫治疗新思路:用COMPASS算法挖掘单细胞数据中的代谢靶点(含差异分析技巧)

本文介绍了如何利用COMPASS算法从单细胞转录组数据中系统推断免疫细胞的代谢活性,为肿瘤免疫治疗提供新的靶点发现思路。文章详细阐述了COMPASS结合流平衡分析的核心原理,并提供了从差异分析到可成药性评估的完整转化路径,旨在帮助研究者精准定位代谢弱点,开发新型免疫代谢疗法。

weixin_29275257的博客 368

Android实现系统联系人字符分组以及字母表导航效果 .

功能的实现结合了网上很多非常的好的实现,小小的优化看下。 实现思路: 1. 获取手机联系人列表:通过Uri uri = Uri.parse("content://com.android.contacts/data/phones");  查询联系人列表 2 联系人的字段非常的多,摘取了NAME = "name", NUMBER = "number", SORT_KEY = "sort_key"

5923

【推荐100个unity插件之27】推荐5种办法实现unity人物布料系统 衣服裙子飘动 头发飘动 胸部抖动 骨骼模拟 配件摆动 尾巴摆动 —— 主要是Magica Cloth 2插件

要实现Unity中的人物布料系统并使其具备动态效果,可以探索多种技术方法。这些方法不仅可以使衣服、裙子、头发等元素自然飘动,还可以实现胸部抖动、骨骼模拟、配件摆动和尾巴摆动等细致效果。本文将深入探讨五种实现这些动态效果的技术方案,从基础的物理模拟到高级的动画控制,帮助你打造逼真的人物表现。本文主要探究Magica Cloth 2的使用,因为我想探究最好的实现方法,而不是探究最多的实现方法。

向宇的博客,专注php/web全栈 unity游戏开发,欢迎大家评论纠错 6306

Android系统联系人全特效实现(上),分组导航和挤压动画(1)

android:layout_marginRight=“10dip” android:src=“@drawable/icon” /> 在这个布局文件中,首先是放入了一个和前面完成一样的分组布局,因为不仅界面头部需要展示分组,在每个分组内的第一个无素之前都需要展示分组布局。然后是加入一个简单的 LinearLayout,里面包含了一个 ImageView 用于显示联系人头像,还包含一个 TextView 用于显示联系人姓名。这样我们的布局文件就全部写完了,下面开始来真正地实现功能。先从简单的开始,新建一个 C

2401_84010224的博客 718

【WRF-DART第一期】WRF/DART概述

【WRF-DART第一期】WRF/DART概述

WW、forever的博客 107

Android 9.0 延时开机动画解决首次开机黑屏和去掉android正在启动的提示框

在9.0的系统产品rom定制化开发中,在一些产品中会出现在首次开机的时候,由于在开机动画播放完以后会出现几秒短暂的黑屏情况,然后进入默认Launcher,这在产品体验上 也是感觉到有点差,所以会要求在去掉这个首次开机黑屏的效果,和在启动过程中的 android is starting这个提示框的这些效果优化,接下来就分析下相关功能, 然后实现这个功能的开发

安卓兼职framework和app工程师的博客 3246
上一篇: android控件属性介绍
下一篇: Android调用手机拍照以及从相册选择照片
火VVVVV
博客等级 码龄16年 87粉丝 3原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值