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

仿微信联系人列表字母侧滑控件, 侧滑控件参考了以下博客:

Android实现ListView的A-Z字母排序和过滤搜索功能

首先分析一下字母侧滑控件应该如何实现,根据侧滑控件的高度和字母的数量来平均计算每个字母应该占据的高度。

在View的onDraw()方法下绘制每一个字母

protected void onDraw(Canvas canvas) {
  super.onDraw(canvas);
  int height = getHeight();// 获取对应高度
  int width = getWidth(); // 获取对应宽度
  int singleHeight = height / getData().size();// 获取每一个字母的高度

  for (int i = 0; i < getData().size(); i++) {
   mPaint.setColor(getLetterColor());//绘制字母的颜色
   mPaint.setTypeface(Typeface.DEFAULT);
   mPaint.setAntiAlias(true);
   mPaint.setTextSize(singleHeight);
   // 如果是选中的状态
   if (i == mPosition) {
    mPaint.setColor(getLetterPressedColor());
    mPaint.setFakeBoldText(true);
   }
   // x坐标等于总体宽度中间的位置减去字符串宽度的一半.
   float xPos = width / 2 - mPaint.measureText(getData().get(i)) / 2;
   float yPos = singleHeight * i + singleHeight;
   canvas.drawText(getData().get(i), xPos, yPos, mPaint);
   mPaint.reset();// 重置画笔
  }

 }

然后再看一下触控事件的拦截处理

 @Override
 public boolean dispatchTouchEvent(MotionEvent event) {
  final int action = event.getAction();
  final float y = event.getY();// 点击y坐标
  final int lastPosition = mPosition;//记录上一次选中字母的位置
  final int position = (int) (y / getHeight() * getData().size());// 点击y坐标所占总高度的比例*b数组的长度就等于点击b中的个数.

  switch (action) {
   //当手指离开
   case MotionEvent.ACTION_UP:
   //设置侧滑控件的背景色
    setBackgroundColor(getBackgroundNormalColor());
    mPosition = -1;
    invalidate();

    if (getOnTouchLetterListener() != null) {
    //回调事件,告知当前手指已经离开当前区域
     getOnTouchLetterListener().onTouchOutside();
    }

    break;

   default:
   //更改当字母为选中状态时控件的背景色
    setBackgroundColor(getBackgroundPressedColor());
    //如果选中字母的位置不等于上一次选中的位置
    if (lastPosition != position) {
     if (position >= 0 && position < getData().size()) {
      if (getOnTouchLetterListener() != null) {
      //回调事件,返回当前选中的字母
       getOnTouchLetterListener().onTouchLetter(getData().get(position));
      }
      mPosition = position;
      invalidate();
     }
    }

    break;
  }
  return true;
 }

 public interface OnTouchLetterListener {

  /**
   * 当接触到某个key的时候会调用;
   * @param s
   */
  void onTouchLetter(String s);

  /**
   * 当离开控件可触摸区域时会调用;
   */
  void onTouchOutside();
 }

侧滑控件完成后, 再分析一下分组界面是怎么实现的,不同分组由不同的字母作为标题,用ListView就可以实现,ListView里使用的Adapter里面有一个方法getItemViewType()方法用于区分返回多种类型的View,这里我们就两种, 一个是标题,一个是联系人信息;顶部里那些新的朋友、群聊等可以用ListView的addHeaderView()实现。但是用最SDK自带的BaseAdapter实现分组的话也不方便,实际上我们可以进一步包装;

首先看一下最基本的Adapter封装:

public abstract class SimpleAdapter<T> extends BaseAdapter {

 protected Context mContext;
 protected List<T> mData;

 public SimpleAdapter(){}

 public SimpleAdapter(Context context, List<T> data){
  init(context, data);
 }

 public void init(Context context, List<T> data){
  this.mContext = context;
  this.mData = data;
 }

 @Override
 public int getCount() {
  return mData.size();
 }

 @Override
 public T getItem(int position) {
  if(checkPositionIsOutOfRange(position)){
   return null;
  }
  return mData.get(position);
 }

 @Override
 public long getItemId(int position) {
  return position;
 }

 @Override
 public abstract View getView(int position, View convertView, ViewGroup parent);

 public void refresh(List<T> data){
  if(data == null){
   this.mData.clear();
  }else{
   this.mData = data;
  }
  notifyDataSetChanged();
 }

 public boolean checkPositionIsOutOfRange(int position){
  if(0 <= position && position < mData.size()){
   return false;
  }
  return true;
 }

 public Context getContext(){
  return mContext;
 }

 public List<T> getData(){
  return mData;
 }
}

这个SimpleAdapter实现了数据基于List的最基本方法的实现,使得每次继承BaseAdapter不用再实现一些基本的方法,接下来再看一下用于更好实现分组的Adapter的进一步封装:

public abstract class SortAdapter<K extends SortKey, V, VH_G extends ViewHolder, VH_C extends ViewHolder> extends SimpleAdapter<Object> {

 public final static int VIEW_TYPE_GROUP = 0;
 public final static int VIEW_TYPE_CHILD = 1;

 private HashMap<SortKey, Integer> mKeyIndex = new HashMap<>();

 public SortAdapter(Context context, Map<K, List<V>> map) {
  init(context, convertMapToList(map));
 }

 public SortAdapter(Context context, List<Object> list) {
  init(context, list);
 }

 /**
  * 转换分组数据为List,并且更新键值的索引
  * @param map
  * @return
  */
 public List<Object> convertMapToList(Map<K, List<V>> map) {
  List<Object> mData = new ArrayList<>();
  mKeyIndex.clear();
  for (Map.Entry<K, List<V>> entry : map.entrySet()) {
   mData.add(entry.getKey());
   mKeyIndex.put(entry.getKey(), mData.size() - 1);
   for (V v : entry.getValue()) {
    mData.add(v);
   }
  }
  return mData;
 }

 public void refresh(Map<K, List<V>> map) {
  super.refresh(convertMapToList(map));
 }

 @Override
 public void refresh(List<Object> data) {
  super.refresh(data);
  mKeyIndex.clear();
 }

 /**
  * 得到键值的索引值
  * @param k
  * @return
  */
 public int getKeyIndex(K k){
  Integer integer = mKeyIndex.get(k);
  if(integer == null){
   return getKeyIndexFromList(k);
  }
  return integer;
 }

 public int getKeyIndexFromList(K k){
  for(int i = 0; i < getCount(); i++){
   Object obj = getItem(i);
   if(obj != null && obj instanceof SortKey){
    if(obj.equals(k)){
     mKeyIndex.put(k, i);
     return i;
    }
   }
  }
  return -1;
 }

 @Override
 public int getItemViewType(int position) {
  Object obj = getItem(position);

  if (obj instanceof SortKey) {
   return VIEW_TYPE_GROUP;
  }
  return VIEW_TYPE_CHILD;
 }

 @Override
 public int getViewTypeCount() {
  return 2;
 }

 @Override
 public int getCount() {
  return mData.size();
 }

 @Override
 public Object getItem(int position) {
  if (0 <= position && position < mData.size()) {
   return mData.get(position);
  }
  return null;
 }

 @Override
 public long getItemId(int position) {
  return position;
 }

 @Override
 public View getView(int position, View convertView, ViewGroup parent) {

  int viewType = getItemViewType(position);

  View view = null;
  Object obj = getItem(position);
  switch (viewType) {
   case VIEW_TYPE_GROUP:
    view = getGroupView((K)obj, position, convertView, parent);
    break;
   case VIEW_TYPE_CHILD:
    view = getChildView((V)obj, position, convertView, parent);
    break;
  }
  return view;
 }

 public View getGroupView(K key, int position, View convertView, ViewGroup parent){
  VH_G vh;
  if(convertView == null){
   convertView = LayoutInflater.from(mContext).inflate(getGroupLayoutId(), null);
   vh = onCreateGroupViewHolder(convertView, parent);
   convertView.setTag(vh);
  }else{
   vh = (VH_G)convertView.getTag();
  }

  onBindGroupViewHolder(vh, key, position);
  return convertView;
 }

 public View getChildView(V value, int position, View convertView, ViewGroup parent){
  VH_C vh;
  if(convertView == null){
   convertView = LayoutInflater.from(mContext).inflate(getChildLayoutId(), null);
   vh = onCreateChildViewHolder(convertView, parent);
   convertView.setTag(vh);
  }else{
   vh = (VH_C)convertView.getTag();
  }

  onBindChildViewHolder(vh, value, position);
  return convertView;
 }

 public abstract @LayoutRes int getGroupLayoutId();

 public abstract VH_G onCreateGroupViewHolder(View convertView, ViewGroup parent);

 public abstract void onBindGroupViewHolder(VH_G vh, K key, int position);

 public abstract @LayoutRes int getChildLayoutId();

 public abstract VH_C onCreateChildViewHolder(View convertView, ViewGroup parent);

 public abstract void onBindChildViewHolder(VH_C vh, V value, int position);

 public interface SortKey {
 }

 public static class ViewHolder{

  public View mParent;
  public ViewHolder(View parent){
   mParent = parent;
  }

  public View findViewById(@IdRes int id){
   return mParent.findViewById(id);
  }
 }

本项目Github地址(基于AndroidStudio构建):
https://github.com/yuhengye/LetterSort

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

(0)

相关推荐

  • Android编程实现通讯录中联系人的读取,查询,添加功能示例

    本文实例讲述了Android编程实现通讯录中联系人的读取,查询,添加功能.分享给大家供大家参考,具体如下: 先加二个读和写权限: <uses-permission android:name="android.permission.READ_CONTACTS" /> <uses-permission android:name="android.permission.WRITE_CONTACTS" /> 具体代码: package com.ebo

  • Android跳转到系统联系人及拨号或短信界面

    现在开发中的功能需要直接跳转到拨号.联系人.短信界面等等,查找了很多资料,自己整理了一下. 1.跳转到拨号界面,代码如下:  1)直接拨打 Intent intentPhone = new Intent(Intent.ACTION_CALL, Uri.parse("tel:" + phoneNumber)); startActivity(intentPhone); 2)跳转到拨号界面 Intent intent = newIntent(Intent.ACTION_DIAL,Uri.pa

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

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

  • Android保存联系人到通讯录的方法

    上一篇文章讲了如何获取所有联系人,这篇文章就讲下怎么保存联系人数据到本机通讯录.这里我就假设你已经拿到了要保存的联系人数据. 因为是一个工具类,所以我这里就只给一个方法了,也是很简单,但是写的没有读取联系人的数据那么多,要保存更多其实看下如何读取的就会了. 直接上源码: /** * 添加联系人到本机 * * @param context * @param contact * @return */ public static boolean addContact(Context context,

  • 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获取手机联系人的方法

    Android 获取系统联系人信息的实例 一.获取手机联系人姓名及手机号 //跳转到系统联系人应用 Intent intent = new Intent(Intent.ACTION_PICK, ContactsContract.Contacts.CONTENT_URI); try { startActivityForResult(intent, Contacts1RequestCode); } catch (Exception e) { LogManager.e("打开联系人信息失败"

  • Android实现获取联系人电话号码功能

    本篇文档主要记录一下获取联系人的电话号码的一种方式. 1.选择联系人 ............ //构造一个隐式的Intent,拉起联系人界面 final Intent pickIntent = new Intent(Intent.ACTION_PICK, ContactsContract.Contacts.CONTENT_URI); mSuspectButton = (Button)v.findViewById(R.id.crime_suspect); mSuspectButton.setOn

  • android如何获取联系人所有信息

    只要是开发和手机通讯录有关的应用,总要学会获取联系人信息,每次都google很麻烦,怎么办? 写一个工具类,获取到通讯录里所有的信息并分好类,至于大家怎么用就不管了,看下代码就都明白了,虽然代码很多,但是很简单,大部分都已分类,如果有没有写上的,大家可以打开自己手机上通讯录数据库,里面的字段都有标明,用的内容提供者,因此我们只需要拿到那个字段名基本上就能取出数据了. 工具类: package com.example.test; import java.util.ArrayList; import

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

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

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

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

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

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

  • 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实现首字母导航条,先看张效果图,具体怎么实现看代码吧 具体的步骤 1.整体布局的显示 2. 实现A-Z的分组 3. 自定义A-Z的导航条 4. 中间显示/隐藏触摸到导航条具体的字母 activity_main.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/re

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

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

  • Android仿微信对话列表滑动删除效果

    微信对话列表滑动删除效果很不错的,借鉴了github上SwipeListView(项目地址:https://github.com/likebamboo/SwipeListView),在其上进行了一些重构,最终实现了微信对话列表滑动删除效果. 实现原理  1.通过ListView的pointToPosition(int x, int y)来获取按下的position,然后通过android.view.ViewGroup.getChildAt(position)来得到滑动对象swipeView  2

  • Android仿Keep运动休息倒计时圆形控件

    仿Keep运动休息倒计时控件,供大家参考,具体内容如下 源码 控件本身非常非常简单,唯一难点在于倒计时期间动态增减时长,如果说动态增减时长是瞬间完成的,倒也没什么难度,但是如果是需要花一定时间做动画的话(见效果图),考虑的逻辑就变多了,这也是我写这个的目的,对应源码中就是plus这个方法.地址: KeepCountdownView 效果 使用方法 xml: <com.KeepCountdownView.KeepCountdownView android:id="@+id/keep1&quo

  • Android仿IOS回弹效果 支持任何控件

    本文实例为大家分享了Android仿IOS回弹效果的具体代码,供大家参考,具体内容如下 效果图: 导入依赖: dependencies { // ... compile 'me.everything:overscroll-decor-android:1.0.4' } RecyclerView 支持线性布局和网格布局管理器(即所有原生Android布局).可以轻松适应支持自定义布局管理器. RecyclerView recyclerView = (RecyclerView) findViewByI

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

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

随机推荐