这篇写下常用的类似通讯录似得效果    右边自定义一个sidebar  左边使用listview实现

效果如下:

1、自定义SideBar

①重写onDraw     计算每个字母所占的高度  就是整体的高度除以要画的字母的个数,所以每个字母的高为依次叠加

因为竖行排列,所以每个字母的宽都一样,每个字母的x为整体的宽度减去该字母的宽度的一半

②重写触摸事件  拿到触摸的y除以总的高度 然后乘以所有字母的个数  就可以拿到点击的是第几个字母,如果该字母改变则进行重绘

③设置回调  点击该字母具体方法由外界实现

public class SideBar extends View {// 触摸事件private OnTouchingLetterChangedListener onTouchingLetterChangedListener;// 26个字母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 float size;private int choose = -1;// 选中private Paint paint = new Paint();private TextView mTextDialog;public void setTextView(TextView mTextDialog) {this.mTextDialog = mTextDialog;}public SideBar(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);init(context);}public SideBar(Context context, AttributeSet attrs) {super(context, attrs);init(context);}public SideBar(Context context) {super(context);init(context);}private void init(Context context) {size = DeviceUtil.dip2px(context, 13);}/*** 重写这个方法*/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++) {if (!isInEditMode()) {paint.setColor(Color.parseColor("#838383"));}//设置是否使用抗锯齿功能,会消耗较大资源,绘制图形速度会变慢。paint.setAntiAlias(true);paint.setTextSize(size);// 选中的状态if (i == choose) {paint.setColor(getResources().getColor(R.color.yellow_light));paint.setFakeBoldText(true); //true为粗体,false为非粗体}// x坐标等于中间-字符串宽度的一半.float xPos = width / 2 - paint.measureText(b[i]) / 2;float yPos = singleHeight * i + singleHeight;canvas.drawText(b[i], xPos, yPos, paint);paint.reset();// 重置画笔}}@SuppressWarnings("deprecation")@Overridepublic 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: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;}/*** 接口** @author coder*/public interface OnTouchingLetterChangedListener {public void onTouchingLetterChanged(String s);}}

2、准备好汉字转拼音的工具类

①将jar包丢到libs目录下

②  汉字转拼音工具类

public class PinYinUtil {/*** 获取汉字的拼音* @param chinese* @return*/public static String getPinYin(String chinese){if(TextUtils.isEmpty(chinese))return null;//输出的格式化对象,用来决定输出字母的大小写,是否带有音标之类HanyuPinyinOutputFormat format = new HanyuPinyinOutputFormat();format.setCaseType(HanyuPinyinCaseType.UPPERCASE);//设置大写字母format.setToneType(HanyuPinyinToneType.WITHOUT_TONE);//设置不带有音汉字进行获取,所以要将字符串转为字符数组,一个一个获取,最后拼接StringBuilder builder = new StringBuilder();char[] chars = chinese.toCharArray();for (int i = 0; i < chars.length; i++) {char c = chars[i];//1.过滤空格if(Character.isWhitespace(c)){//如果是空格,则忽略即可continue;}//2.简单判断是否是汉字:一个字节范围是-128~127,所以汉字一定大于127if(c > 127){//说明有可能是汉字,那么利用Pinyin4j的api进行获取try {//由于多音字的存在,返回的是数组,比如:单: {dan, chan ,shan}String[] pinyinArr = PinyinHelper.toHanyuPinyinStringArray(c, format);if(pinyinArr!=null){//问题来了:取哪个拼音?答:暂时只能取第1个//为啥呢?:首先大部分汉字只有一个读音,对于多音字的情况,由于我们实在无能为力去//判断它的真实读音,也只能取第1个罢了。builder.append(pinyinArr[0]);}} catch (Exception e) {e.printStackTrace();//如果异常,说明不是正确的汉字,直接忽略}}else {//说明肯定不是汉字,一般是英文字母,我们选择直接拼接builder.append(c);}}return builder.toString();}
}

3、将数据放到listview上展示

①布局如下

<FrameLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"><ListViewandroid:id="@+id/school_friend_member"android:layout_width="match_parent"android:layout_height="match_parent"android:cacheColorHint="@android:color/transparent"android:divider="@mipmap/bg_cut_line"android:dividerHeight="1px"android:fadingEdge="none"android:listSelector="@android:color/transparent"android:scrollbars="none"></ListView><TextViewandroid:id="@+id/school_friend_dialog"android:layout_width="80.0dip"android:layout_height="80.0dip"android:layout_gravity="center"android:background="@drawable/bg_show_head_toast"android:gravity="center"android:textColor="#ffffffff"android:textSize="30.0dip"android:visibility="invisible" /><com.hiteamtech.ddbes.ui.view.SideBarandroid:id="@+id/school_friend_sidrbar"android:layout_width="30dp"android:layout_height="match_parent"android:layout_gravity="right|center" />
</FrameLayout>

②初始化

mListView = (ListView) findViewById(R.id.school_friend_member);
mSideBar = (SideBar) findViewById(R.id.school_friend_sidrbar);
mDialog = (TextView) findViewById(R.id.school_friend_dialog);
mSideBar.setOnTouchingLetterChangedListener(this);mSideBar.setTextView(mDialog);

③给获取到的集合排序

Collections.sort(complete, new Comparator<UserBean>() {@Overridepublic int compare(UserBean o1, AUserBean o2) {String pinying1;String pinying2;if(o1.getAssetname()!=null){pinying1= PinYinUtil.getPinYin(o1.getUserName());}else{pinying1= PinYinUtil.getPinYin("z");}if(o2.getAssetname()!=null){pinying2= PinYinUtil.getPinYin(o2.getUserName());}else{pinying2=PinYinUtil.getPinYin("z");}return pinying1.compareTo(pinying2);}
});

④给listview设置adapter

item布局:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="fill_parent"android:layout_height="wrap_content"android:gravity="center_vertical"android:orientation="vertical"><TextViewandroid:id="@+id/catalog"android:layout_width="fill_parent"android:layout_height="wrap_content"android:background="#F9F9F9"android:paddingBottom="5dip"android:paddingLeft="5dip"android:paddingTop="5dip"android:textColor="#454545" /><TextViewandroid:id="@+id/line"android:layout_width="fill_parent"android:layout_height="1px"android:background="@mipmap/bg_cut_line" /><LinearLayoutandroid:id="@+id/content"android:layout_width="fill_parent"android:layout_height="60dip"android:background="@color/white"android:orientation="horizontal"android:paddingBottom="5dp"android:paddingLeft="10dp"android:paddingRight="10dp"android:paddingTop="5dp"><com.hiteamtech.ddbes.ui.view.CircleImageViewandroid:id="@+id/head"android:layout_width="45dp"android:layout_height="45dp"android:layout_marginLeft="10dp"android:layout_gravity="center_vertical"android:src="@mipmap/headimg_default" /><TextViewandroid:id="@+id/title"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center_vertical"android:layout_marginLeft="10dip"android:ellipsize="end"android:gravity="center_vertical"android:singleLine="true"android:textColor="#323232"android:textSize="16sp"tools:text="xxxx" /></LinearLayout></LinearLayout>

adapter如下:

public class InviteFriendListAdapter extends BaseAdapter implements SectionIndexer {private LayoutInflater inflater;private Context mContext;private List<UserBean> list;public InviteFriendListAdapter(Context context, List<UserBean> list) {this.mContext = context;this.list = list;}/*** 当ListView数据发生变化时,调用此方法来更新ListView** @param list*/public void updateListView(List<UserBean> list) {this.list = list;notifyDataSetChanged();}@Overridepublic int getCount() {return list.size();}@Overridepublic Object getItem(int position) {return list.get(position);}@Overridepublic long getItemId(int position) {return position;}@Overridepublic View getView(int position, View convertView, ViewGroup parent) {ViewHolder holder = null;if (convertView == null) {
//            inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);inflater = LayoutInflater.from(mContext);convertView = inflater.inflate(R.layout.invitation_friends_item_layout, null);holder = new ViewHolder();holder.ivHead = (CircleImageView) convertView.findViewById(R.id.head);holder.tvTitle = (TextView) convertView.findViewById(R.id.title);holder.tvLetter = (TextView) convertView.findViewById(R.id.catalog);holder.tvLine = (TextView) convertView.findViewById(R.id.line);holder.tvContent = (LinearLayout) convertView.findViewById(R.id.content);convertView.setTag(holder);} else {holder = (ViewHolder) convertView.getTag();}final UserBean phoneContactBean = list.get(position);if (phoneContactBean != null) {//判断该首字母是否是第一次出现if (isfirstshow(position)) {holder.tvLetter.setVisibility(View.VISIBLE);holder.tvLetter.setText(PinYinUtil.getPinYin(mlist.get(position).getUserName()).substring(0,1).toUpperCase());holder.tvLine.setVisibility(View.VISIBLE);} else {holder.tvLetter.setVisibility(View.GONE);holder.tvLine.setVisibility(View.GONE);}holder.tvTitle.setText(phoneContactBean.getUserName());Glide.with(mContext).load(phoneContactBean.getHeadimg()).asBitmap().error(R.mipmap.headimg_default).into(holder.ivHead);holder.tvContent.setOnClickListener(new OnCheckFriendClick(phoneContactBean));}return convertView;}class ViewHolder {CircleImageView ivHead;TextView tvLetter;TextView tvTitle;TextView tvLine;CheckBox checkFriendCb;LinearLayout tvContent;}public boolean isfirstshow(int  position) {//获取该位置的拼音String sectionForPosition = PinYinUtil.getPinYin(mlist.get(position).getUserName());//获取首字母String firstletter =sectionForPosition.substring(0,1).toUpperCase();//判断该位置之前有没有出现过该字母  如果出现过  则不是首次出现,返回falsefor(int i=0;i<position;i++){String letter = PinYinUtil.getPinYin(mlist.get(i).getUserName()).substring(0, 1).toUpperCase();if(firstletter.equals(letter)){return false;}}return true;}public List<UserBean> getList() {return list;}
}

4、将sidebar与listview联系起来  当触摸到sidebar的某个字母时  移动到listview首次出现该首字母的位置

实现SideBar.OnTouchingLetterChangedListener接口

给sidebar 设置回调 :mSideBar.setOnTouchingLetterChangedListener(this);

@Override
public void onTouchingLetterChanged(String s) {int position=0;for(int i=0;i<mlist.size();i++){//获取名字的首字母String letter = PinYinUtil.getPinYin(arrayList.get(i).getUserName()).substring(0,1).toUpperCase();if(letter.equals(s)){//第一次出现的位置position=i;//将listview滚动到该位置mListView.setSelection(position);break;}}

小结:文章有点长 ,有问题的地方还希望大家多多指出

Android 仿微信通讯录相关推荐

  1. Android仿微信通讯录

    Android仿微信通讯录 分3部: 1.listview实现显示头像.名字(太简单,这里就不写了) 通讯录页面xml布局代码: <LinearLayout xmlns:android=&quo ...

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

    *本篇文章已授权微信公众号 guolin_blog (郭霖)独家发布 转载请标明出处: http://blog.csdn.net/zxt0601/article/details/52355199 本文 ...

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

    前言: 仿微信通讯录搜索功能,通过汉字或拼音首字母找到匹配的联系人并显示匹配的位置 一:先看效果图 字母索引 搜索匹配 二:功能分析 1:汉字转拼音 通讯录汉字转拼音(首个字符当考虑姓氏多音字), 现 ...

  4. android 通讯录 首字母索引,android仿微信通讯录搜索(匹配拼音,字母,索引位置标记颜色)...

    前言: 仿微信通讯录搜索功能,通过汉字或拼音首字母找到匹配的联系人并显示匹配的位置 一:先看效果图 字母索引 搜索匹配 二:功能分析 1:汉字转拼音 通讯录汉字转拼音(首个字符当考虑姓氏多音字), 现 ...

  5. 【Android 仿微信通讯录 导航分组列表-下】自定义View为RecyclerView打造右侧索引导航栏IndexBar

    本篇文章已授权微信公众号 guolin_blog (郭霖)独家发布 转载请标明出处: http://blog.csdn.net/zxt0601/article/details/52420706 本文出 ...

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

    本文是Android导航分组列表系列上,因时间和篇幅原因分上下,最终上下合璧,完整版效果如下:   上部残卷效果如下:两个ItemDecoration,一个实现悬停头部分组列表功能,一个实现分割线(官 ...

  7. android 仿微信demo————微信通讯录界面功能实现(移动端,服务端)

    android 仿微信demo----微信启动界面实现 android 仿微信demo----注册功能实现(移动端) android 仿微信demo----注册功能实现(服务端) android 仿微 ...

  8. php仿微信底部菜单,Android实现简单底部导航栏 Android仿微信滑动切换效果

    Android仿微信滑动切换最终实现效果: 大体思路: 1. 主要使用两个自定义View配合实现; 底部图标加文字为一个自定义view,底部导航栏为一个载体,根据需要来添加底部图标; 2. 底部导航栏 ...

  9. android仿微信的activity平滑水平切换动画,Android实现简单底部导航栏 Android仿微信滑动切换效果...

    Android实现简单底部导航栏 Android仿微信滑动切换效果 发布时间:2020-10-09 19:48:00 来源:脚本之家 阅读:96 作者:丶白泽 Android仿微信滑动切换最终实现效果 ...

最新文章

  1. Linux 进程状态【转】
  2. phantomjs linux 中文不显示,linux 安装phantomJs 用于截图,处理中文乱码,和样式问题...
  3. centos7.6arm安装mysql8.0.17_Centos yum安装 MySQL 5.7
  4. 面向对象(继承,多态)
  5. [css] 你知道CSS中的字母“C“代表什么吗?
  6. autotools入门笔记(一)
  7. C语言:(旧)用字符串自由输入计算的计算器(加减乘除)
  8. 第四届HTML5峰会 - 上海站
  9. 特斯拉Model X成NASA官方宇航员转运车辆,已打上NASA标志
  10. python time模块和random 模块
  11. 过拟合的含义、出现原因及解决方案
  12. fio 磁盘I/O测试工具
  13. 文本文档怎么改格式html,文本文档怎么显示txt-文本文档怎么改格式
  14. 破解版 中易广告联盟程序 v6.0
  15. sourcetree拉取项目时报错,解决两个冲突
  16. 带通滤波器是什么,它的原理是什么
  17. mysql migration 使用_DbMigration的使用方法
  18. BZOJ 4826 HNOI2017 影魔
  19. Python程序不使用函数将字符大写
  20. flash基本操作二-库面板和元件创建

热门文章

  1. docker基础篇--有它就够了
  2. 计算机毕业设计Java河池市旅游信息系统(源码+系统+mysql数据库+lw文档)
  3. Android 在build.gradle文件中读取json文件
  4. itunes计算机无法启动,itunes无法成功更新后无法打开
  5. 该网页无法正常运作xxxx将您重定向的次数过多
  6. 和ts一般怎么玩_AG首发大换血,成功复仇TS,发了工资的TS谁也打不赢?
  7. LODOP打印控件使用问题总结
  8. 哈啰:学拼多多的套路,走美团的老路
  9. python编程求1!+2!+…+n!_python计算阶乘和的方法(1!+2!+3!+...+n!)
  10. python毕业设计项目源码选题(5)校园网站系统毕业设计毕设作品开题报告开题答辩PPT