android仿微信联系人索引列表功能

前言

  因为自己在做的一个小软件里面需要用到从A-Z排序的ListView,所以自然而然的想到了微信的联系人,我想要的就是那样的效果。本来没打算自己去写,想要第三方写好的东西,搜了几个之后发现有的太复杂了,有的简单是简单,但是不符合我的要求,所以我就来个整合,把复杂性和简单性合二为一。

实现

  先来看效果图吧:

要点分析

  要实现这样的效果需要考虑下面的几个问题:

  • 右边字母栏的绘制
  • 点击效果的实现
  • 汉字按A-Z的排序问题
  • 正常的Item和字母分隔符的Item的实现

  下面我们就解决这几个问题,然后就可以出现上面的效果了。

【第一步】

  我们需要先自定义一个类,就叫SlideBar吧,让它继承Button,然后我们覆盖onDraw方法,绘制字母a-z就可以出现右边字母栏的效果了。

看一下源码:

public class SlideBar extends Button{ 

 public interface OnTouchAssortListener{
 public void onTouchAssortListener(String s);
 } 

 // 分类
 private static final String[] ASSORT_TEXT = {"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 mPaint = new Paint();
 private int mSelectIndex = -1;
 private OnTouchAssortListener mListener = null;
 private Activity mAttachActivity;
 PopupWindow mPopupWindow = null;
 View layoutView;
 TextView text;

 public SlideBar(Context context){
 this(context,null);
 } 

 public SlideBar(Context context, AttributeSet attrs) {
 this(context, attrs,0);
 } 

 public SlideBar(Context context, AttributeSet attrs, int defStyle){
 super(context, attrs, defStyle);
 mAttachActivity = (Activity)context;
 init(context);
 }
 private void init(Context context) {
 layoutView = LayoutInflater.from(context).inflate(R.layout.alert_dialog_menu_layout, null);
 text = (TextView) layoutView.findViewById(R.id.content);
 }

 public void setOnTouchAssortListener(OnTouchAssortListener listener) {
 this.mListener = listener;
 }

 @Override
 protected void onDraw(Canvas canvas){
 super.onDraw(canvas);
 int nHeight = getHeight();
 int hWidth = getWidth();
 int nAssortCount = ASSORT_TEXT.length;
 int nInterval = nHeight / nAssortCount;

 for (int i = 0; i < nAssortCount; i++){
  mPaint.setAntiAlias(true); // 抗锯齿
  mPaint.setTypeface(Typeface.DEFAULT_BOLD); // 默认粗体
  mPaint.setColor(Color.parseColor("#5f5f5f")); // 白色
  if (i == mSelectIndex){
  // 被选择的字母改变颜色和粗体
  mPaint.setColor(Color.parseColor("#3399ff"));
  mPaint.setFakeBoldText(true);
  mPaint.setTextSize(30);
  }
  float xPos = hWidth / 2 - mPaint.measureText(ASSORT_TEXT[i]) / 2; // 计算字母的X坐标
  float yPos = nInterval * i + nInterval; // 计算字母的Y坐标
  canvas.drawText(ASSORT_TEXT[i], xPos, yPos, mPaint);
  mPaint.reset();
 }
 } 

 @Override
 public boolean dispatchTouchEvent(MotionEvent event) {
 //判断是哪一个字母被点击了
 int nIndex = (int) (event.getY() / getHeight() * ASSORT_TEXT.length);
 if (nIndex >= 0 && nIndex < ASSORT_TEXT.length){
  switch (event.getAction()){
  case MotionEvent.ACTION_MOVE:
  // 如果滑动改变
  if (mSelectIndex != nIndex){
   mSelectIndex = nIndex;
   showCharacter(ASSORT_TEXT[mSelectIndex]);
   if (mListener != null){
   mListener.onTouchAssortListener(ASSORT_TEXT[mSelectIndex]);
   }
  }
  break;
  case MotionEvent.ACTION_DOWN:
  mSelectIndex = nIndex;
  showCharacter(ASSORT_TEXT[mSelectIndex]);
  if (mListener != null){
   mListener.onTouchAssortListener(ASSORT_TEXT[mSelectIndex]);
  } 

  break;
  case MotionEvent.ACTION_UP:
  disShowCharacter();
  mSelectIndex = -1;
  break;
  }
 } else {
  mSelectIndex = -1;
  disShowCharacter();
 }
 invalidate();
 return true;
 }

 private void disShowCharacter() {
 if (mPopupWindow != null) {
  mPopupWindow.dismiss();
  mPopupWindow=null;
 }
 }

 /**
 * 显示弹出的字符
 * @param string
 */
 private void showCharacter(String string){

 if (mPopupWindow != null){
  text.setText(string);
 } else{
  mPopupWindow = new PopupWindow(layoutView, 100, 100, false);
  mPopupWindow.showAtLocation(mAttachActivity.getWindow().getDecorView(), Gravity.CENTER, 0, 0);
 }
 text.setText(string);
 }
}

  就先看onDraw方法,其他的内容先不看,首先得到控件的宽和高,然后计算每一个字母应该占据的高度为多少,然后在每一个字母所占空间的中间绘制该字母就可以了,代码比较简单,这一部分就不需要详解了。

【第二步】

  我们需要添加一个点击事件,当点击SlideBar的时候,首先可以看到的是右边栏被点击的字母变大来区别于没被点击的字母,然后弹出一个类似Dialog的东西,显示被点中的字母,这个效果也很好实现。
  在SlideBar里面我们还需要覆盖的一个方法是dispatchTouchEvent(),我们点中SlideBar之后,接下来的动作可能是滑动和抬起,我们需要对点击之后的动作进行响应,如果是抬起的话,那么显示出来的类似dialog的东西就要消失,变大的字母也要回复原样,如果是接着滑动,滑到某一个字母的时候,对应的字母就要变大和显示出来。
  从上面的源码可以看到,字母变大的效果很好实现,把绘制被选中的字母的Paint对象的textsize的值变大就可以了,然后那个类似dialog的东西是用PopupWindow来实现的,当点击和滑动的时候就显示PopupWindow,抬起或者滑出SlideBar范围的时候就让PopupWindow消失。最后需要注意的是invalidate()这个方法千万不要忘记调用了,这个是用来进行画面的重绘。

【第三步】

  我认为最重要也是最难的就是汉字按A-Z的排序了。不过还好,这个已经有人实现了,我们就来所谓的“拿来主义”吧。在工程里面有一个CharacterParser类,这个类封装了对汉字转拼音的操作,其中getSelling(String s)方法的作用是传入汉字字符串得到汉字的拼音,果然是好方法,我喜欢!!这样我们就得到了要显示的汉字字符串的拼音首字母,然后将所有的字符串按照字母进行排序就可以得到一个从A-Z的有序的列表了。因为ListView一般都是绑定一个List对象,然后List对象里面保存一系列的对象,这里我就用一个对象来说:

public class DataBean {

 public static final int TYPE_CHARACTER = 0;
 public static final int TYPE_DATA = 1;
 private int item_type;
 private String item_en;
 private String name;
 private String phone;
 /*其他成员*/

 public DataBean(String name,String phone,int type){
 CharacterParser parser = CharacterParser.getInstance();
 this.name = name;
 this.phone = phone;
 this.item_type = type;
 this.item_en = parser.getSelling(name).toUpperCase().trim();
 if(!item_en.matches("[A-Z]+")){
  item_en = "#"+item_en;
 }
 }

 /*
 *省略geter和seter方法
 */
}

  这个对象里面需要注意的是两个成员变量,item_type和item_en,分别表示该对象是要显示的正常对象还是字母分隔符对象,根据item_type的不同,我们在写Adapter的getView方法的时候就可以返回不同的View对象,然后就可以实现效果图中的正常的Item和字母分割符Item了。item_en表示的是name变量也就是汉字字符串的拼音字符串,主要是用来获取首字母和进行字符串之间的比较。

  现在假设已经有了一个List对象,里面保存了一些DataBean,那么问题来了,如何把这些DataBean对象按拼音字符串进行排序以及如何在List对象里面添加表示字母分隔符的DataBean对象呢?

  首先解决排序的问题,这个比较简单:

  这里用到了Collections的sort方法,这个方法有两个参数,一个就是带排序的List对象,另一个是实现了Comparator接口的类的对象,用来说明如何进行排序,用哪一个成员变量来进行排序。

  PinyinComparator这个类实现了Comparator:

public class PinyinComparator implements Comparator<DataBean>{
 public int compare(DataBean o1, DataBean o2){
 if (o1.getItem_en().equals("@")
  || o2.getItem_en().equals("#")){
  return -1;
 } else if (o1.getItem_en().equals("#")
  || o2.getItem_en().equals("@")) {
  return 1;
 } else {
  return o1.getItem_en().compareTo(o2.getItem_en());
 }
 }
}

  可以看到,两个DataBean对象按照变量item_en也就是拼音字符串来进行排序,这样实现起来比较方便,不需要自己去写排序的算法了,当然也不反对大家自己去实现排序。

  经过Collections的sort函数排序之后,现在List对象里面保存的DataBean对象已经是按照A-Z进行排序的了,现在我们要做的就是在这些对象里面插入一些用来表示字母分隔符DataBean的对象,这个实现应该比较简单,我用的方法比较笨/(ㄒoㄒ)/~~

public class ListUtil {
 public static void sortList(List<DataBean> list){
 List<DataBean> _List = new ArrayList<DataBean>();
 Collections.sort(list, new PinyinComparator());
 DataBean dataBean = new DataBean(getFirstCharacter(list.get(0).getItem_en()), "",DataBean.TYPE_CHARACTER);
 String currentCharacter = getFirstCharacter(list.get(0).getItem_en());
 _List.add(dataBean);
 _List.add(list.get(0));
 for(int i=1;i<list.size();i++){
 if(getFirstCharacter(list.get(i).getItem_en()).compareTo(currentCharacter)!=0){
 currentCharacter = getFirstCharacter(list.get(i).getItem_en());
 dataBean = new DataBean(currentCharacter, "",DataBean.TYPE_CHARACTER);
 _List.add(dataBean);
 }
 _List.add(list.get(i));
 }
 list.clear();
 for(DataBean bean:_List){
 list.add(bean);
 }
 }
 public static String getFirstCharacter(String str){
 return str.substring(0, 1);
 }
}

  这个类就实现了往List对象里面添加一些表示字母分隔符的对象,通过设置item_type变量的值不同,在Adapter里面根据这个值返回不同的View就可以实现不同的Item显示。

  好了,到现在只剩一个问题了,那就是点击了字母之后,ListView设置该字母对应的Item在第一个显示,这个实现也不难,得到了被点中的字母之后,遍历所有的DataBean对象,然后找到和当前字母匹配的第一个字母分隔符对象,然后得到该Item的position的值,设置ListView被选中的Item的position为找到的Item的position即可。

  终于,所有的问题解决了,看看现在自己能不能实现这样的效果了呢?如果不行的话可以参考一个我的源码。

小结

  本来我也是对这个不是太懂,但是强迫自己去看源码,因为网上的大神写的东西可能并不是100%满足自己的要求,所以自己能看懂源码的话就可以自己去修改了。

源码下载在这里。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • android开发教程之使用listview显示qq联系人列表

    首先还是xml布局文件,在其中添加ListView控件: 主布局layout_main.xml 复制代码 代码如下: <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"

  • Android实现可浏览和搜索的联系人列表

    通过这篇文章,我想说明一下如何创建一个可搜索的"联系人列表"Android应用程序.使用这个应用程序,用户可以通过使用导航按钮浏览所有保存的联系人和根据联系人名称搜索联系人.该应用程序还可以显示联系人的照片(如果可用). 要浏览联系人列表可以使用<<,<,>和>>按钮. 要搜索联系人的用户在"搜索名称"文本框中键入联系人名称,然后单击"搜索"按钮.点击"清除搜索"按钮,清除"搜索名

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

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

  • Android仿微信联系人列表字母侧滑控件

    仿微信联系人列表字母侧滑控件, 侧滑控件参考了以下博客: Android实现ListView的A-Z字母排序和过滤搜索功能 首先分析一下字母侧滑控件应该如何实现,根据侧滑控件的高度和字母的数量来平均计算每个字母应该占据的高度. 在View的onDraw()方法下绘制每一个字母 protected void onDraw(Canvas canvas) { super.onDraw(canvas); int height = getHeight();// 获取对应高度 int width = get

  • android仿微信联系人索引列表功能

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

  • Android仿微信右滑返回功能的实例代码

    先上效果图,如下: 先分析一下功能的主要技术点,右滑即手势判断,当滑到一直距离时才执行返回,并且手指按下的位置是在屏幕的最左边(这个也是有一定范围的),  这些可以实现onTouchEvent来实现. 接着就是返回时,有滑动效果,很显然这个是Acitivty切换动画实现的.好啦,分析完了就开干.下面上代码: @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()){ case Mot

  • Android仿微信联系人按字母排序

    App只要涉及到联系人的界面,几乎都是按照字母排序以及导航栏的方式.既然这个需求这么火,于是开始学习相关内容,此篇文章是我通过参考网上资料独立编写和总结的,希望多多少少对大家有所帮助,写的不好,还请各位朋友指教. 效果图如下: 实现这个效果,需要三个知识点 : 1:将字符串 进行拼音分类 2:ExpandableListView 二级扩展列表 3:右边字母分类View 我们先一个一个来了解解决方案,再上代码. 实现字母分类: 字母分类又分为三个小要点:一个是将中文转化为拼音,一个是实现按照字母的

  • Android实现iPhone晃动撤销输入功能 Android仿微信摇一摇功能

    很多程序中我们可能会输入长文本内容,比如短信,写便笺等,如果想一次性撤销所有的键入内容,很多手机需要一直按住退格键逐字逐句的删除,稍稍麻烦,不过在iPhone上,有个人性化的功能,当我们想要去撤销刚刚输入的所有内容的时候,可以轻轻晃动手机,会弹出提示框,点击确定就可以清空内容,如下图: 在android中,一般手机貌似没有定制这个功能,不过我们可以自己去实现这样的功能,放置在我们的项目程序中,体现更人性化的设计,思路很简单,主要是利用手机内置的加速度传感器装置,其实大家一定会想到微信的"摇一摇&

  • Android仿微信联系人字母排序效果

    本文实例为大家分享了Android联系人字母排序的具体代码,供大家参考,具体内容如下 实现思路:首先说下布局,整个是一个相对布局,最下面是一个listview,listview上面是一个自定义的view(右边显示字母),最上面是一个textview(屏幕中间的方块). 首先说一下右边自定义view,字母是画到view上面的,首先计算一下view的高度,然后除以存放字母数组的长的,得到每个字符的高度:每个字母的宽度都是一样的,所以这里直接设置30sp: listview显示的是108个梁山好汉的名

  • Android仿微信activity滑动关闭效果

    Android仿微信activity滑动关闭功能 1.利用具体利用v4包下的slidingPaneLayout实现透明的activity,代码如下: BaseActivity: public class BaseSlideCloseActivity extends AppCompatActivity implements SlidingPaneLayout.PanelSlideListener { @Override protected void onCreate(Bundle savedIns

  • android仿微信好友列表功能

    android studio实现微信好友列表功能,注意有一个jar包我没有放上来,请大家到MainActivity中的那个网址里面下载即可,然后把pinyin4j-2.5.0.jar复制粘贴到项目的app/libs文件夹里面,然后clean项目就可以使用了 实现效果图: (1)在build.gradle中引用第三方的类库 compile 'com.android.support:recyclerview-v7:26.0.0-alpha1' compile files('libs/pinyin4j

  • Android仿微信通讯录列表侧边栏效果

    先看Android仿微信通讯录列表侧边栏效果图 这是比较常见的效果了吧 列表根据首字符的拼音字母来排序,且可以通过侧边栏的字母索引来进行定位. 实现这样一个效果并不难,只要自定义一个索引View,然后引入一个可以对汉字进行拼音解析的jar包--pinyin4j-2.5.0即可 首先,先来定义侧边栏控件View,只要直接画出来即可. 字母选中项会变为红色,且滑动时背景会变色,此时SideBar并不包含居中的提示文本 public class SideBar extends View { priva

  • Android仿微信@好友功能 输入@跳转、删除整块

    最近在做聊天功能的时候,有一个需求是仿照微信做@好友的功能,本来以为挺简单,但是做到这块的时候,发现和想象的有点不一样,什么整块删除,块可编辑,总之,加个@的功能很简单,但是要做和微信的一样还是费了一些功夫,下面是一个demo仅供参考,防止遗忘 先上个效果图 就是这么个功能 1. 分析需求 输入@跳转到联系人界面,选中一个或者多个好友返回到当前界面 按退格键删除整块内容 块内的内容可编辑,编辑完了之后将不附带@功能,只是单纯的文字 2. 开始编码 既然是文本输入首先继承EditText自定义一个

随机推荐