通过SectionIndexer实现微信通讯录

这里主要参考了使用SectionIndexer实现微信通讯录的效果

在这里做个记录

效果图

页面使用RelativeLayout,主要分为三个部分,match_parent的主listView,右边字母的SideBar,还有就是微信那种点击字母时浮动的一个TextView

布局:

  fragment_contacts.xml

 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     <ListView
 7         android:layout_width="match_parent"
 8         android:layout_height="match_parent"
 9         android:listSelector="@android:color/transparent"
10         android:id="@+id/listFragmentContacts"/>
11     <TextView
12         android:id="@+id/textFragmentContacts"
13         android:layout_width="wrap_content"
14         android:layout_height="wrap_content"
15         android:layout_centerInParent="true"
16         android:padding="20dp"
17         android:textSize="40sp"
18         android:textColor="@android:color/white"
19         android:background="#33000000"
20         android:visibility="gone"
21         tools:visibility="visible"
22         tools:text="A"/>
23     <lee.example.com.testdj.customWeight.ContactsMySideBar
24         android:id="@+id/sideBarFragmentContacts"
25         android:layout_width="24dp"
26         android:layout_height="match_parent"
27         android:layout_alignParentRight="true"/>
28 </RelativeLayout>

  layout_contacts_item.xml

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <LinearLayout 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="wrap_content"
 6     android:orientation="vertical">
 7
 8     <!--section,表示组-->
 9     <TextView
10         android:id="@+id/tvSectionContactsItem"
11         android:layout_width="match_parent"
12         android:layout_height="wrap_content"
13         android:gravity="left"
14         android:textSize="22sp"
15         android:textColor="#666666"
16         tools:text="section"/>
17
18     <TextView
19         android:id="@+id/tvNormalContactsItem"
20         android:layout_width="match_parent"
21         android:layout_height="wrap_content"
22         android:padding="6dp"
23         android:textColor="@android:color/black"
24         android:background="@android:color/white"
25         android:textSize="20sp"
26         tools:text="text"/>
27 </LinearLayout>

实现:

首先,自定义View来实现SideBar,ContactsMySideBar.java

  1 public class ContactsMySideBar extends View{
  2
  3     private static final String TAG = "ContactsMySideBar";
  4
  5     private SectionIndexer sectionIndexer;
  6     private final char[] letters = new char[]{‘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‘};
  7     private Paint paint;                    //画笔用来绘制字母
  8     private ListView listView;
  9     private int focusedIndex = -1;          //点击选中的索引
 10     private int drawWidth, drawHeight;      //绘制单个字母的宽高
 11
 12     public interface OnTouchChangedListener{
 13         void onTouchDown(char c);
 14         void onTouchUp();
 15     }
 16
 17     private OnTouchChangedListener listener;
 18
 19     public void setOnTouchChangedListener(OnTouchChangedListener listener){
 20         this.listener = listener;
 21     }
 22
 23     public void setListView(ListView listView){
 24         this.listView = listView;
 25         sectionIndexer = (SectionIndexer) listView.getAdapter();
 26     }
 27
 28     public ContactsMySideBar(Context context) {
 29         super(context);
 30         init();
 31     }
 32
 33     public ContactsMySideBar(Context context, AttributeSet attrs) {
 34         super(context, attrs);
 35         init();
 36     }
 37
 38     public ContactsMySideBar(Context context, AttributeSet attrs, int defStyle) {
 39         super(context, attrs, defStyle);
 40         init();
 41     }
 42
 43     private void init(){
 44         //设置画笔属性
 45         paint = new Paint();
 46         paint.setColor(Color.GRAY);
 47         paint.setTextSize(18f);
 48         paint.setTextAlign(Paint.Align.CENTER);
 49     }
 50
 51     @Override
 52     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
 53         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
 54         drawWidth = getMeasuredWidth()/2;           //宽度为sideBar的一半
 55         drawHeight = getMeasuredHeight()/letters.length;    //设置高度
 56     }
 57
 58     @Override
 59     protected void onDraw(Canvas canvas) {
 60         for (int i = 0; i < letters.length; i++){
 61             canvas.drawText(String.valueOf(letters[i]), drawWidth, drawHeight + (i * drawHeight), paint);
 62         }
 63     }
 64
 65     @Override
 66     public boolean onTouchEvent(MotionEvent event) {
 67         int pointerY = (int) event.getY();
 68         int selectedIndex = pointerY / drawHeight;
 69         if (selectedIndex >= letters.length){
 70             selectedIndex = letters.length - 1;
 71         }else if(selectedIndex < 0){
 72             selectedIndex = 0;
 73         }
 74
 75         switch (event.getAction()){
 76             case MotionEvent.ACTION_DOWN:
 77                 //点击时设置为半透明
 78                 setBackgroundColor(Color.parseColor("#33000000"));
 79             case MotionEvent.ACTION_MOVE:
 80                 if (sectionIndexer == null){
 81                     sectionIndexer = (SectionIndexer) listView.getAdapter();
 82                 }
 83 //                Log.d(TAG, letters[selectedIndex] + "");
 84                 //根据数组中的元素获取对应的组位置
 85                 int position = sectionIndexer.getPositionForSection(letters[selectedIndex]);
 86                 Log.d(TAG, "" + position);
 87                 if (position == -1){
 88                     return true;
 89                 }
 90                 if (selectedIndex != 0){
 91                     if (position != 0){
 92                         //改变当前listView所处位置
 93                         listView.setSelection(position);
 94                     }
 95                 }else {
 96                     listView.setSelection(position);
 97                 }
 98
 99                 //重绘SideBar
100                 invalidate();
101                 if (null != listener){
102                     listener.onTouchDown(letters[selectedIndex]);
103                 }
104                 break;
105             case MotionEvent.ACTION_UP:
106             case MotionEvent.ACTION_CANCEL:
107                 //松开手指取消背景色
108                 setBackgroundResource(android.R.color.transparent);
109                 invalidate();
110                 if (null != listener){
111                     listener.onTouchUp();
112                 }
113                 break;
114         }
115         return true;
116     }
117 }

这部分代码很简单,重写了OnMeasure和OnDraw来绘制SideBar,在OnTouchEvent中写出了SideBar的响应事件

定义listView的adapter

SideBarAdapter.java
  1 public class SideBarAdapter extends BaseAdapter implements SectionIndexer{
  2
  3     private static final String TAG = "SideBarAdapter";
  4
  5     private Context context;
  6     private List<ContactsModel> modelList;
  7     private LayoutInflater layoutInflater;
  8
  9     public SideBarAdapter(Context context, List<ContactsModel> modelList){
 10         this.context = context;
 11         this.modelList = modelList;
 12         layoutInflater = LayoutInflater.from(context);
 13     }
 14
 15     @Override
 16     public int getCount() {
 17         return modelList.size();
 18     }
 19
 20     @Override
 21     public ContactsModel getItem(int i) {
 22         return modelList.get(i);
 23     }
 24
 25     @Override
 26     public long getItemId(int i) {
 27         return i;
 28     }
 29
 30     @Override
 31     public View getView(int i, View convertView, ViewGroup viewGroup) {
 32         Holder holder;
 33         if (convertView == null){
 34             convertView = layoutInflater.inflate(R.layout.layout_contacts_item, viewGroup, false);
 35             holder = new Holder();
 36             holder.normalTv = (TextView) convertView.findViewById(R.id.tvNormalContactsItem);
 37             holder.sectionTv = (TextView) convertView.findViewById(R.id.tvSectionContactsItem);
 38             convertView.setTag(holder);
 39         }else {
 40             holder = (Holder) convertView.getTag();
 41         }
 42         String text = modelList.get(i).getName();
 43         setSectionTv(i, holder, text);
 44         setNormalTv(holder, text);
 45
 46         return convertView;
 47     }
 48
 49     private void setNormalTv(Holder holder, String text){
 50         holder.normalTv.setText(text);
 51     }
 52
 53     private void setSectionTv(int position, Holder holder, String text){
 54         //获取每个item字符串的头一个字符
 55 //        Log.d(TAG, ZhCharactersUtil.changeToSpell(text));
 56         char firstChar = ZhCharactersUtil.changeToSpell(text).toUpperCase().charAt(0);
 57         //若为第一个位置直接设置组view就行
 58         if (position == 0) {
 59             holder.sectionTv.setVisibility(View.VISIBLE);
 60             holder.sectionTv.setText((firstChar + "").toUpperCase());
 61         }
 62         //若不是,需判断当前item首字母与上一个item首字母是否一致,再设置组view
 63         else {
 64             String preLabel = modelList.get(position - 1).getName();
 65             //获取上一个item的首字母
 66             char preFirstChar = ZhCharactersUtil.changeToSpell(preLabel).toUpperCase().charAt(0);
 67             if (firstChar != preFirstChar) {
 68                 holder.sectionTv.setVisibility(View.VISIBLE);
 69                 holder.sectionTv.setText((firstChar + "").toUpperCase());
 70             } else {
 71                 //若与上一个item首字母一致则不需要重复设置组view
 72                 holder.sectionTv.setVisibility(View.GONE);
 73             }
 74         }
 75     }
 76
 77     @Override
 78     public Object[] getSections() {
 79         //获取组信息的数组,比如这里可以返回char[]{‘A‘,‘B‘,...}
 80         return new Object[0];
 81     }
 82
 83     @Override
 84     public int getPositionForSection(int section) {
 85         //根据组信息获取索引
 86         for (int i = 0; i < modelList.size(); i++) {
 87             String str = modelList.get(i).getName();
 88             char firstChar = ZhCharactersUtil.changeToSpell(str).toUpperCase().charAt(0);
 89             if (firstChar == section) {
 90                 return i;
 91             }
 92         }
 93         return 0;
 94     }
 95
 96     @Override
 97     public int getSectionForPosition(int i) {
 98         //根据索引获取组信息,这里不做处理
 99         return 0;
100     }
101
102     private final class Holder {
103         TextView normalTv, sectionTv;
104     }
105 }

这里用到了一个第三方,jpinyin,是用来对汉字进行处理,转换成拼音等等,ZhCharactersUtil.java就是用来处理汉字的,我这里只需要取拼音的第一个字母

1 public class ZhCharactersUtil {
2     public static String changeToSpell(String string){
3         char[] chars = PinyinHelper.getShortPinyin(string).toCharArray();
4         return chars[0] + "";
5     }
6
7 }

这里的ContactsModel里边只有两个属性,一个name,一个firstCharacter,其中firstCharacter是用来进行排序的,上边adapter的代码可以用modelList.get(i).getFirstCharacter()来简化一些,偷懒了,所以开始写好了就放在那没动,这里这个model就不记录了。

在Activity中使用,我这里是在fragment中使用,都是一样的

1 private ListView listView;
2     //悬浮的textView
3     private TextView maskText;
4     private ContactsMySideBar sideBar;
5
6     //然后对他们进行初始化
 1 private void initData(){
 2         ContactsModel model1 = new ContactsModel("张一");
 3         ContactsModel model2 = new ContactsModel("张二");
 4         ContactsModel model3 = new ContactsModel("李一");
 5         ContactsModel model4 = new ContactsModel("李二");
 6         ContactsModel model5 = new ContactsModel("赵一");
 7         ContactsModel model6 = new ContactsModel("赵二");
 8         ContactsModel model7 = new ContactsModel("王三");
 9         ContactsModel model8 = new ContactsModel("王二");
10         ContactsModel model9 = new ContactsModel("阿张");
11         ContactsModel model10 = new ContactsModel("不行");
12         ContactsModel model11 = new ContactsModel("特别");
13         ContactsModel model12 = new ContactsModel("将就");
14         ContactsModel model13 = new ContactsModel("公司");
15         ContactsModel model14 = new ContactsModel("空是");
16         ContactsModel model15 = new ContactsModel("好附件打开");
17         ContactsModel model16 = new ContactsModel("现在");
18         ContactsModel model17 = new ContactsModel("哦跑");
19
20         ContactsModel model18 = new ContactsModel("aaasss");
21         ContactsModel model19 = new ContactsModel("bbb");
22         ContactsModel model20 = new ContactsModel("s");
23         ContactsModel model21 = new ContactsModel("jjj");
24         ContactsModel model22 = new ContactsModel("oot");
25
26         modelList.add(model1);
27         modelList.add(model2);
28         modelList.add(model3);
29         modelList.add(model4);
30         modelList.add(model5);
31         modelList.add(model6);
32         modelList.add(model7);
33         modelList.add(model8);
34         modelList.add(model9);
35         modelList.add(model10);
36         modelList.add(model11);
37         modelList.add(model12);
38         modelList.add(model13);
39         modelList.add(model14);
40         modelList.add(model15);
41         modelList.add(model16);
42         modelList.add(model17);
43 //        modelList.add(model18);
44 //        modelList.add(model19);
45 //        modelList.add(model20);
46 //        modelList.add(model21);
47 //        modelList.add(model22);
48         Collections.sort(modelList, new Comparator<ContactsModel>() {
49             @Override
50             public int compare(ContactsModel contactsModel, ContactsModel t1) {
51                 return contactsModel.getFirstCharacter().compareTo(t1.getFirstCharacter());
52             }
53         });
54
55         adapter = new SideBarAdapter(getContext(), modelList);
56         listView.setAdapter(adapter);
57         sideBar.setListView(listView);
58         sideBar.setOnTouchChangedListener(new ContactsMySideBar.OnTouchChangedListener() {
59             @Override
60             public void onTouchDown(char c) {
61                 maskText.setText(c + "");
62                 maskText.setVisibility(View.VISIBLE);
63             }
64
65             @Override
66             public void onTouchUp() {
67                 maskText.setVisibility(View.GONE);
68             }
69         });
70     }

这里添加了一些假数据,完成。

时间: 2024-10-19 18:00:50

通过SectionIndexer实现微信通讯录的相关文章

类似于微信通讯录的界面Demo

这几天遇到一个项目需要向微信通讯录那样展示联系人,这里我做了一个简单的例子,希望可以帮助大家 先来看下界面的实现效果          上面的是在搜索框搜索时的结果,和点击后边的字母跳转到相应 的字母对应名字地方,并且显示你选择的字母 好了,现在我们来整理一下思路,怎么实现这中效果呢. 第一步,我们肯定是要有一个这样的界面 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" androi

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

[Android 仿微信通讯录 导航分组列表-上]使用ItemDecoration为RecyclerView打造带悬停头部的分组列表 一 概述 本文是Android导航分组列表系列上,因时间和篇幅原因分上下,最终上下合璧,完整版效果如下: 上部残卷效果如下:两个ItemDecoration,一个实现悬停头部分组列表功能,一个实现分割线(官方demo) 网上关于实现带悬停分组头部的列表的方法有很多,像我看过有主席的自定义ExpandListView实现的,也看过有人用一个额外的父布局里面套 Rec

微信通讯录不见了?或者只显示部分?删掉它就解决了!

微信的通讯录显示不全,只有部分或者都不见了,这种情况,一般是一个电脑有几个微信版本造成的! 今天下午,有个同事居然还用着1.5版本的微信,而现在最新的已经是2.6版本的了,也是服了,还出现微信的图片发不出去,按回车,图片就不见了,这个问题,升级到最新版微信就可以了,但是通讯录问题,却是不能解决,我研究了下,删掉以下文件夹,问题就可以完美解决了! 删掉文件夹路径为"C:\User\Administrator\Documents\WeChat Files\",目录下以你的微信号命名的文件夹

导出微信通讯录到 Excel

/** * 将 contacts 转化成你需要的格式 * 这里可以任意发挥 * @param contacts * @returns {*} */ function formatContacts(contacts) { return contacts.map(({NickName, Sex, RemarkName}) => { return { '昵称': NickName, '备注': RemarkName } }) } /** * 加载 script * @param url * @retu

小柒来科普微信通讯录拉群打群的相关知识

所谓通讯录粉,就是客户提供精准用户数据,机房批量添加,规模大的机房一天通过十几万的精准好友不是问题.所以对于销售变现团队成熟都是个巨大的需求.通讯录导粉引流方式介绍:1,客户预付款财务,提供上粉主号2,安排技术客服对接,教客户安装加粉软件3,根据客户加粉需求,安排小号加为好友4,小号批量加粉,推送客户名片方式给客户加粉5,加满客户指定数量粉丝后,通知客户下线客户端微信通讯录导粉相比其他泛粉,优势在哪里? 通讯录粉丝,其实是精准粉丝的一种,可以根据可以行业,去指定加对应的手机号码数据,也可以客户提

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

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

类似微信通讯录界面的排序方法及中文转拼音的方法

最近做一个类似微信的通讯录列表,因为本人也算个新手,然后呢,就遇到点问题.难点在对昵称的排序上,顺带着也就找了找中文转拼音的方法. 废话不多说,直接贴代码吧 1.首先要对昵称字符串进行中文转拼音,这个比较简单,写到NSString分类里面就行. - (NSString *)pinyin; { NSMutableString *str = [self mutableCopy]; CFStringTransform(( CFMutableStringRef)str, NULL, kCFStringT

揭秘微信通讯录协议代加好友拉小群平台

前天写了篇文章"如何设置一个微信号,日加2000好友",发到各大自媒体平台去结果爆的一发不可收拾. 本来看到小白也正常,但是林子大了什么鸟都有,耐心跟他解释,这种玩法不行,他娘的立刻翻脸说我骗子,所谓众口难调!! 所以先给新手普及下,群/wixd爆粉软件:爆群就是可以无限添加群里好友,爆wxid数据就是把wxid数据导入软件批量添加,打招呼没有上限,且不会因为使用该软件而被限制登录(发垃圾信息过多被投诉的例外),理论上一个号一天可以干满.对号的要略高,需要活跃度高的号才可以爆.(什么是

一天协议机房微信通讯录协议拉群拼的是质量

微信是一个非常大的平台 很多人都围绕微信做营销,微信具有社交.聊天.朋友圈.支付转账等功能,是一个可以迅速变现的营销平台. 微信加粉系统一直有很多公司和技术人员在开发. 做通讯录拉群/导粉 (拼的是质量和服务) 奉劝各位,别贪小便宜! 谨记!谨记!谨记! 很多人知道我是做通讯录拉群/导粉 而且价格有点小贵,只要钱到位,各种姿势我都会 但是别拿市面上120一个群跟我比. 我做通讯录导粉/拉群遵从几个点 1.不参水 2.不做二导,没有重复粉 3.导粉小号不出售 4.资料不泄漏外传 原文地址:http