仿联系人定位悬浮

效果图



导包:

[html]  view plain  copy
  1. compile 'com.android.support:recyclerview-v7:23.1.1'  
  2. compile 'ca.barrenechea.header-decor:header-decor:0.2.6'  

这里还用到一个Jar包

[html]  view plain  copy
  1. 链接: https://pan.baidu.com/s/1X-dcGEomFlmMWu3QYx_iOg 密码: xi73  
免费下载


1.直接复制拼音工具类

[html]  view plain  copy
  1. public class PinYinUtils {  
  2.   
  3.     public static String getPinYin(String text){  
  4.         char[] chars = text.toCharArray();  
  5.   
  6.         StringBuilder sb = new StringBuilder();  
  7.   
  8.         HanyuPinyinOutputFormat format = new HanyuPinyinOutputFormat();  
  9.   
  10.         //取消音调  
  11.         format.setToneType(HanyuPinyinToneType.WITHOUT_TONE);  
  12.         //大写  
  13.         format.setCaseType(HanyuPinyinCaseType.UPPERCASE);  
  14.   
  15.         for ( char ch : chars ) {  
  16.             if(Character.isWhitespace(ch)){  
  17.                 //如果是空格  
  18.                 continue;  
  19.             }  
  20.   
  21.             if(ch > 128 || ch < -127){  
  22.                 try{  
  23.                     //数组是有多音字  
  24.                     String[] array = PinyinHelper.toHanyuPinyinStringArray(ch, format);  
  25.                     sb.append(array[0]);  
  26.   
  27.                 }catch (BadHanyuPinyinOutputFormatCombination e){  
  28.                     e.getMessage();  
  29.                 }  
  30.             }else{  
  31.                 //#$%^  
  32.                 return "#";  
  33.             }  
  34.         }  
  35.   
  36.         return sb.toString();  
  37.   
  38.     }  
  39.   
  40. }  


2.ToastUtils   这个随意可以不复制

[html]  view plain  copy
  1. public class Utils {  
  2.   
  3.     private static Toast toast;  
  4.   
  5.     public static void showToast(Context context, String text){  
  6.         if (toast == null)  
  7.         toast = Toast.makeText(context, text, Toast.LENGTH_SHORT);  
  8.         toast.setText(text);  
  9.         toast.show();  
  10.     }  
  11. }  

3.我们先自定义一个右边的字母索引

[html]  view plain  copy
  1. public class QuickIndexBar extends View {  
  2.     private Paint paint;  
  3.     private float mCellHeight;  
  4.     private int mWidth;  
  5.   
  6.     //26英文字母  
  7.     private static final String[] LETTERS = new String[]{"#","A", "B", "C", "D",  
  8.             "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q",  
  9.             "R", "S", "T", "U", "V", "W", "X", "Y", "Z"};  
  10.   
  11.     private int mHeight;  
  12.     private float mTextHeight;  
  13.     private int currentIndex = -1;  
  14.   
  15.     private OnLetterChangeListener onLetterChangeListener;  
  16.   
  17.     public OnLetterChangeListener getOnLetterChangeListener() {  
  18.         return onLetterChangeListener;  
  19.     }  
  20.   
  21.     public void setOnLetterChangeListener(OnLetterChangeListener onLetterChangeListener) {  
  22.         this.onLetterChangeListener = onLetterChangeListener;  
  23.     }  
  24.   
  25.     //暴露接口  
  26.     public interface OnLetterChangeListener{  
  27.         void onLetterChange(String letter);  
  28.         void onReset();  
  29.     }  
  30.   
  31.     public QuickIndexBar(Context context) {  
  32.         this(context, null);  
  33.     }  
  34.   
  35.     public QuickIndexBar(Context context, AttributeSet attrs) {  
  36.         this(context, attrs, 0);  
  37.     }  
  38.   
  39.     public QuickIndexBar(Context context, AttributeSet attrs, int defStyleAttr) {  
  40.         super(context, attrs, defStyleAttr);  
  41.         paint = new Paint();  
  42.   
  43. //        画笔默认是 黑色  设置为白色  
  44.   
  45.         //设置字体大小  
  46.         paint.setTextSize(dip2px(context, 14));  
  47.   
  48.         //抗锯齿  
  49.         paint.setAntiAlias(true);  
  50.   
  51.         // 获取字体的高度  
  52.         Paint.FontMetrics fontMetrics = paint.getFontMetrics();  
  53.   
  54.         //  下边界  - 上边界  
  55.   
  56.         //ceil 天花板    0.1  1  
  57.         mTextHeight = (float) Math.ceil(fontMetrics.descent - fontMetrics.ascent);  
  58.     }  
  59.   
  60.     // 测量完成  改变的时候调用  
  61.     @Override  
  62.     protected void onSizeChanged(int w, int h, int oldw, int oldh) {  
  63.         super.onSizeChanged(w, h, oldw, oldh);  
  64.   
  65.         //获取测量后的宽度和高度  
  66.         mWidth = getMeasuredWidth();  
  67.         mHeight = getMeasuredHeight();  
  68.   
  69.         //每个字母的高度  
  70.         mCellHeight = mHeight * 1.0f / LETTERS.length;  
  71.     }  
  72.   
  73.     // 怎么画  
  74.     @Override  
  75.     protected void onDraw(Canvas canvas) {  
  76.         super.onDraw(canvas);  
  77.   
  78.         //遍历并绘制26英文字母  
  79.         for (int i = 0; i < LETTERS.length; i++) {  
  80.             String text = LETTERS[i];  
  81.   
  82.             //测量字体宽度  
  83.             float mTextWidth = paint.measureText(text);  
  84.   
  85.             //获取字母的xy坐标,坐标默认为字母左下角  
  86.             float x = mWidth / 2 - mTextWidth / 2;  
  87.             float y = mCellHeight / 2 + mTextHeight / 2 + mCellHeight * i;  
  88.   
  89.             //判断当前索引并绘制相应的颜色  
  90.             if (currentIndex == i){  
  91.                 //当索引为当前的字母时绘制的颜色  
  92.                 paint.setColor(Color.parseColor("#000000"));  
  93.             }else{  
  94.                 paint.setColor(Color.parseColor("#FF9696"));  
  95.             }  
  96.             // 字.画字();  
  97.             canvas.drawText(text, x, y, paint);  
  98.         }  
  99.     }  
  100.   
  101.     //触摸事件  
  102.     @Override  
  103.     public boolean onTouchEvent(MotionEvent event) {  
  104.         switch (event.getAction()) {  
  105.             case MotionEvent.ACTION_DOWN:  
  106.                 // 计算当前点击的 字母  
  107.                 float downY = event.getY();  
  108.                 // 1.1  ---  1  1.4 --- 1  1.5 --- 1  
  109.                 currentIndex = (int) (downY / mCellHeight);  
  110.                 if (currentIndex < 0 || currentIndex > LETTERS.length - 1) {  
  111.                 } else {  
  112. //                    Utils.showToast(getContext(), LETTERS[currentIndex]);  
  113.                     if (onLetterChangeListener != null){  
  114.                         onLetterChangeListener.onLetterChange(LETTERS[currentIndex]);  
  115.                     }  
  116.                 }  
  117.   
  118.                 //重新绘制  
  119. //                invalidate();  
  120.                 break;  
  121.             case MotionEvent.ACTION_MOVE:  
  122.                 // 计算当前点击的 字母  
  123.                 float moveY = event.getY();  
  124.                 currentIndex = (int) (moveY / mCellHeight); // 1.1  ---  1  1.4 --- 1  1.5 --- 1  
  125.   
  126.                 if (currentIndex < 0 || currentIndex > LETTERS.length - 1) {  
  127.                 } else {  
  128.                     if (onLetterChangeListener != null){  
  129.                         onLetterChangeListener.onLetterChange(LETTERS[currentIndex]);  
  130.                     }  
  131.                 }  
  132.                 //重新绘制  
  133. //                invalidate();  
  134.                 break;  
  135.             case MotionEvent.ACTION_UP:  
  136.                 currentIndex = -1;  
  137.                 if (onLetterChangeListener != null){  
  138.                     onLetterChangeListener.onReset();  
  139.                 }  
  140.   
  141.                 break;  
  142.         }  
  143.         //重新绘制  
  144.         invalidate();  
  145.   
  146.         //   返回true  为了收到 move  & up 事件  
  147.         return true;  
  148.     }  
  149.   
  150.   
  151.   
  152.     /**  
  153.      * 根据手机的分辨率从 dip 的单位 转成为 px(像素)  
  154.      */  
  155.     public static int dip2px(Context context, float dpValue) {  
  156.         final float scale = context.getResources().getDisplayMetrics().density;  
  157.         return (int) (dpValue * scale + 0.5f);  
  158.     }  
  159. }  


4.然后到主函数

[html]  view plain  copy
  1. public class MainActivity extends AppCompatActivity {  
  2.   
  3.     private android.support.v7.widget.RecyclerView rv;  
  4.     private QuickIndexBar QIBar;  
  5.   
  6.     public static final String[] NAMES = new String[] { "宋江", "卢俊义", "吴用",  
  7.             "公孙胜", "关胜", "林冲", "秦明", "呼延灼", "花荣", "柴进", "李应", "朱仝", "鲁智深",  
  8.             "武松", "董平", "张清", "杨志", "徐宁", "索超", "戴宗", "刘唐", "李逵", "史进", "穆弘",  
  9.             "雷横", "李俊", "阮小二", "张横", "阮小五", " 张顺", "阮小七", "杨雄", "石秀", "解珍",  
  10.             " 解宝", "燕青", "朱武", "黄信", "孙立", "宣赞", "郝思文", "韩滔", "彭玘", "单廷珪",  
  11.             "魏定国", "萧让", "裴宣", "欧鹏", "邓飞", " 燕顺", "杨林", "凌振", "蒋敬", "吕方",  
  12.             "郭 盛", "安道全", "皇甫端", "王英", "扈三娘", "鲍旭", "樊瑞", "孔明", "孔亮", "项充",  
  13.             "李衮", "金大坚", "马麟", "童威", "童猛", "孟康", "侯健", "陈达", "杨春", "郑天寿",  
  14.             "陶宗旺", "宋清", "乐和", "龚旺", "丁得孙", "穆春", "曹正", "宋万", "杜迁", "薛永", "施恩",  
  15.             "周通", "李忠", "杜兴", "汤隆", "邹渊", "邹润", "朱富", "朱贵", "蔡福", "蔡庆", "李立",  
  16.             "李云", "焦挺", "石勇", "孙新", "顾大嫂", "张青", "孙二娘", " 王定六", "郁保四", "白胜",  
  17.             "时迁", "段景柱" };  
  18.   
  19.     private List<ContactsBean> namelist = new ArrayList<>();  
  20.     private LinearLayoutManager manager;  
  21.   
  22.     @Override  
  23.     protected void onCreate(Bundle savedInstanceState) {  
  24.         super.onCreate(savedInstanceState);  
  25.         setContentView(R.layout.activity_main);  
  26.   
  27.         this.rv = (RecyclerView) findViewById(R.id.id_recyclerview);  
  28.         QIBar = (QuickIndexBar) findViewById(R.id.qib);  
  29.   
  30.   
  31.         ContactsBean bean;  
  32.         for (int i = 0; i < NAMES.length; i++) {  
  33.             bean = new ContactsBean(NAMES[i]);  
  34.             namelist.add(bean);  
  35.         }  
  36.         //对集合进行排序  
  37.         Collections.sort(namelist);  
  38.   
  39.         //条目间的间隔线  
  40.         DividerDecoration divider = new DividerDecoration.Builder(MainActivity.this)  
  41.                 .setHeight(R.dimen.default_divider_height)  
  42.                 .setColorResource(R.color.colorAccent)  
  43.                 .build();  
  44.   
  45.         manager = new LinearLayoutManager(MainActivity.this);  
  46.   
  47.         rv.setHasFixedSize(true);  
  48.         rv.setLayoutManager(manager);  
  49.         rv.addItemDecoration(divider);  
  50.   
  51.         final ContactsAdapter adapter = new ContactsAdapter(MainActivity.this, namelist);  
  52.         adapter.setOnItemClickListener(new ContactsAdapter.OnItemClickListener() {  
  53.             @Override  
  54.             public void onClick(int position,String name) {  
  55.                 Toast.makeText(MainActivity.this,"您点击了"+position+"行"+name,Toast.LENGTH_SHORT).show();  
  56.             }  
  57.             @Override  
  58.             public void onLongClick(int position,String name) {  
  59.                 Toast.makeText(MainActivity.this,"您长按点击了"+position+"行"+name,Toast.LENGTH_SHORT).show();  
  60.             }  
  61.         });  
  62.   
  63.         //设置悬浮索引  
  64.         StickyHeaderDecoration decor = new StickyHeaderDecoration(adapter);  
  65.   
  66.         rv.setAdapter(adapter);  
  67.         rv.addItemDecoration(decor, 1);  
  68.   
  69.   
  70.         //侧拉索引改变监听  
  71.         QIBar.setOnLetterChangeListener(new QuickIndexBar.OnLetterChangeListener() {  
  72.             @Override  
  73.             public void onLetterChange(String letter) {  
  74.   
  75.                 for (int i = 0; i < namelist.size(); i++) {  
  76.   
  77.                     if(letter.equals(namelist.get(i).pinyin.charAt(0) + "")) {  
  78.   
  79.                         int position = adapter.getPositionForSection(namelist.get(i).pinyin.charAt(0));  
  80.                         if(position != -1){  
  81.                             //滑动到指定位置  
  82.                             manager.scrollToPositionWithOffset(position,0);  
  83.                         }  
  84.                         break;  
  85.                     }  
  86.                 }  
  87.             }  
  88.   
  89.             @Override  
  90.             public void onReset() {  
  91.   
  92.             }  
  93.         });  
  94.         QIBar.setOnTouchListener(new View.OnTouchListener() {  
  95.             @Override  
  96.             public boolean onTouch(View v, MotionEvent event) {  
  97.                 switch (event.getAction()) {  
  98.                     case MotionEvent.ACTION_DOWN:  
  99.                         QIBar.setBackgroundColor(Color.parseColor("#ffe4e4"));  
  100.                         break;  
  101.                     case MotionEvent.ACTION_UP:  
  102.                         QIBar.setBackgroundColor(Color.argb(0,0,0,0));  
  103.                         break;  
  104.                 }  
  105.                 return false;  
  106.             }  
  107.         });  
  108.     }  
  109.   
  110. }  


5.然后到到主布局

[html]  view plain  copy
  1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  2.     xmlns:tools="http://schemas.android.com/tools"  
  3.     android:layout_width="match_parent"  
  4.     android:layout_height="match_parent" >  
  5.   
  6.     <android.support.v7.widget.RecyclerView  
  7.         android:id="@+id/id_recyclerview"  
  8.         android:divider="#ffff0000"  
  9.         android:dividerHeight="10dp"  
  10.         android:background="#ffffff"  
  11.         android:layout_width="match_parent"  
  12.         android:layout_height="match_parent" />  
  13.   
  14.     <fan.recyclerviewdemo.QuickIndexBar  
  15.         android:layout_alignParentRight="true"  
  16.         android:layout_width="23dp"  
  17.         android:layout_height="match_parent"  
  18.         android:padding="6dp"  
  19.         android:id="@+id/qib" />  
  20.   
  21. </RelativeLayout>  


6.再写一个Recycler适配器

[html]  view plain  copy
  1. public class ContactsAdapter extends RecyclerView.Adapter<ContactsAdapter.ViewHolder> implements  
  2.         StickyHeaderAdapter<ContactsAdapter.HeaderHolder> {  
  3.   
  4.     private LayoutInflater mInflater;  
  5.     private List<ContactsBean> namelist;  
  6.     private OnItemClickListener mOnItemClickListener;  
  7.   
  8.     private char lastChar = '\u0000';  
  9.     private int DisplayIndex = 0;  
  10.   
  11.     public ContactsAdapter(Context context, List<ContactsBean> namelist) {  
  12.         mInflater = LayoutInflater.from(context);  
  13.         this.namelist = namelist;  
  14.     }  
  15.   
  16.     @Override  
  17.     public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {  
  18.         final View view = mInflater.inflate(R.layout.item_contacts_item, viewGroup, false);  
  19.         return new ViewHolder(view);  
  20.     }  
  21.   
  22.     //条目文本填充  
  23.     @Override  
  24.     public void onBindViewHolder(ViewHolder viewHolder, final int i) {  
  25.         viewHolder.text_item.setText(namelist.get(i).name);  
  26.         if( mOnItemClickListener!= null){  
  27.             viewHolder.itemView.setOnClickListener( new View.OnClickListener() {  
  28.                 @Override  
  29.                 public void onClick(View v) {  
  30.                     mOnItemClickListener.onClick(i,namelist.get(i).name);  
  31.                 }  
  32.             });  
  33.             viewHolder. itemView.setOnLongClickListener( new View.OnLongClickListener() {  
  34.                 @Override  
  35.                 public boolean onLongClick(View v) {  
  36.                     mOnItemClickListener.onLongClick(i,namelist.get(i).name);  
  37.                     return false;  
  38.                 }  
  39.             });  
  40.         }  
  41.     }  
  42.   
  43.     @Override  
  44.     public int getItemCount() {  
  45.         return namelist.size();  
  46.     }  
  47.   
  48.     public long getHeaderId(int position) {  
  49.   
  50.         //这里面的是如果当前position与之前position重复(内部判断)  则不显示悬浮标题栏  如果不一样则显示标题栏  
  51.   
  52.         char ch = namelist.get(position).pinyin.charAt(0);  
  53.   
  54.         if(lastChar == '\u0000'){  
  55.   
  56.             lastChar = ch;  
  57.   
  58.             return DisplayIndex;  
  59.         }else{  
  60.   
  61.             if(lastChar == ch){  
  62.   
  63.                 return DisplayIndex;  
  64.   
  65.             }else{  
  66.   
  67.                 lastChar = ch;  
  68.                 DisplayIndex ++ ;  
  69.                 return DisplayIndex;  
  70.             }  
  71.   
  72.         }  
  73.   
  74.     }  
  75.   
  76.     public HeaderHolder onCreateHeaderViewHolder(ViewGroup parent) {  
  77.         final View view = mInflater.inflate(R.layout.item_contacts_head, parent, false);  
  78.         return new HeaderHolder(view);  
  79.     }  
  80.   
  81.     //悬浮标题栏填充文本  
  82.     public void onBindHeaderViewHolder(HeaderHolder viewholder, int position) {  
  83.         viewholder.header.setText(namelist.get(position).pinyin.charAt(0) + "");  
  84.     }  
  85.   
  86.   
  87.     static class ViewHolder extends RecyclerView.ViewHolder {  
  88.         public TextView text_item;  
  89.         public ImageView imageView_item;  
  90.   
  91.         public ViewHolder(View itemView) {  
  92.             super(itemView);  
  93.             text_item = (TextView) itemView.findViewById(R.id.text_item);  
  94.             imageView_item= (ImageView) itemView.findViewById(R.id.image_item);  
  95.         }  
  96.     }  
  97.   
  98.     static class HeaderHolder extends RecyclerView.ViewHolder {  
  99.         public TextView header;  
  100.   
  101.         public HeaderHolder(View itemView) {  
  102.             super(itemView);  
  103.   
  104.             header = (TextView) itemView;  
  105.         }  
  106.     }  
  107.   
  108.     /**  
  109.      * 获得指定首字母的位置  
  110.      * @param ch  
  111.      * @return  
  112.      */  
  113.     public int getPositionForSection(char ch){  
  114.   
  115.         for (int i = 0; i < getItemCount(); i++) {  
  116.             char firstChar = namelist.get(i).pinyin.charAt(0);  
  117.             if (firstChar == ch) {  
  118.                 return i;  
  119.             }  
  120.         }  
  121.         return -1;  
  122.   
  123.     }  
  124.     public interface OnItemClickListener{  
  125.         void onClick( int position,String name);  
  126.         void onLongClick( int position,String name);  
  127.     }  
  128.     public void setOnItemClickListener(OnItemClickListener onItemClickListener ){  
  129.         this. mOnItemClickListener=onItemClickListener;  
  130.     }  
  131.   
  132. }  

7.我们还需要头部和中间部分  然后创建这两个布局  

item_contacts_head

[html]  view plain  copy
  1. <TextView  
  2.     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="20dp"  
  6.     android:background="#F4F4F4"  
  7.     android:textSize="12sp"  
  8.     android:gravity="center_vertical"  
  9.     android:paddingLeft="15dp"  
  10.     android:paddingRight="16dp"  
  11.     android:textAppearance="?android:attr/textAppearanceMedium"  
  12.     android:textColor="#333333"  
  13.     tools:text="Sample text">  
  14.   
  15. </TextView>  

item_contacts_item

[html]  view plain  copy
  1. <LinearLayout  
  2.     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="60dp"  
  6.     android:orientation="horizontal"  
  7.     android:gravity="center_vertical"  
  8.     android:background="#ffffff">  
  9.     <ImageView  
  10.         android:id="@+id/image_item"  
  11.         android:layout_width="38dp"  
  12.         android:layout_height="wrap_content"  
  13.         android:src="@mipmap/ic_launcher"  
  14.         android:layout_marginLeft="15dp"/>  
  15.   
  16.     <TextView  
  17.         android:id="@+id/text_item"  
  18.         android:layout_width="match_parent"  
  19.         android:layout_height="wrap_content"  
  20.         android:layout_marginLeft="35dp"  
  21.         android:gravity="center_vertical"  
  22.         android:textSize="13sp"  
  23.         tools:text="Sample text"  
  24.         />  
  25. </LinearLayout>  


8.最后需要一个排序类

[html]  view plain  copy
  1. public class ContactsBean implements Comparable<ContactsBean>{  
  2.   
  3.     public String name;  
  4.     public String pinyin;  
  5.     private ImageView image;  
  6.   
  7.     public ContactsBean(String name){  
  8.         this.name = name;  
  9.         this.pinyin = PinYinUtils.getPinYin(name);  
  10.         this.image = image;  
  11.   
  12.     }  
  13.   
  14.     @Override  
  15.     public int compareTo(ContactsBean another) {  
  16.         return this.pinyin.compareTo(another.pinyin);  
  17.     }  
  18. }  

猜你喜欢

转载自blog.csdn.net/Duanmuyang/article/details/80103062
今日推荐