快速索引 (对View的自定义)
快速索引应用场景: 微信好友列表, 联系人通讯录, 应用管理, 文件管理等。
快速索引7步曲: *1. A-Z索引的绘制. * 2. 处理Touch事件. * 3. 提供使用监听\回调 * 4. 汉字转换成拼音. * 5. 进行排序展示. * 6. 进行分组. * 7. 将自定义控件和ListView合体.1.A-Z索引的绘制
protected void onDraw(Canvas canvas) { for (int i = 0; i < LETTERS.length; i++) { String text = LETTERS[i]; // 计算坐标 int x = (int) (cellWidth / 2.0f - mPaint.measureText(text) / 2.0f); // 获取文本的高度 Rect bounds = new Rect();// 矩形 mPaint.getTextBounds(text, 0, text.length(), bounds); int textHeight = bounds.height(); int y = (int) (cellHeight / 2.0f + textHeight / 2.0f + i * cellHeight); // 根据按下的字母, 设置画笔颜色 mPaint.setColor(touchIndex == i ? Color.GRAY : Color.WHITE); // 绘制文本A-Z canvas.drawText(text, x, y, mPaint); }}
2 处理Touch事件
int touchIndex = -1;@Overridepublic boolean onTouchEvent(MotionEvent event) { int index = -1; switch (MotionEventCompat.getActionMasked(event)) { case MotionEvent.ACTION_DOWN: // 获取当前触摸到的字母索引 index = (int) (event.getY() / cellHeight); if(index >= 0 && index < LETTERS.length){ // 判断是否跟上一次触摸到的一样 if(index != touchIndex) { if(listener != null){ listener.onLetterUpdate(LETTERS[index]); } Log.d(TAG, "onTouchEvent: " + LETTERS[index]); touchIndex = index; } } break; case MotionEvent.ACTION_MOVE: index = (int) (event.getY() / cellHeight); if(index >= 0 && index < LETTERS.length){ // 判断是否跟上一次触摸到的一样 if(index != touchIndex){ if(listener != null){ listener.onLetterUpdate(LETTERS[index]); } Log.d(TAG, "onTouchEvent: " + LETTERS[index]); touchIndex = index; } } break; case MotionEvent.ACTION_UP: touchIndex = -1; break; default: break; } invalidate(); return true;}
3.提供使用监听\回调
QuickIndexBar bar = (QuickIndexBar) findViewById(R.id.bar); // 设置监听 bar.setListener(new OnLetterUpdateListener() {......}
4.汉字转换成拼音
开源包:pingyin4j.jarpublic static String getPinyin(String str) { HanyuPinyinOutputFormat format = new HanyuPinyinOutputFormat(); format.setCaseType(HanyuPinyinCaseType.UPPERCASE); format.setToneType(HanyuPinyinToneType.WITHOUT_TONE); StringBuilder sb = new StringBuilder(); char[] charArray = str.toCharArray(); for (int i = 0; i < charArray.length; i++) { char c = charArray[i]; // 如果是空格, 跳过 if(Character.isWhitespace(c)){ continue; } if(c >= -127 && c < 128){ // 肯定不是汉字 sb.append(c); }else { String s = ""; try { // 通过char得到拼音集合. 单 -> dan, shan s = PinyinHelper.toHanyuPinyinStringArray(c, format)[0]; sb.append(s); } catch (BadHanyuPinyinOutputFormatCombination e) { e.printStackTrace(); sb.append(s); } } } return sb.toString();}
显示字母
protected void showLetter(String letter) { tv_center.setVisibility(View.VISIBLE); tv_center.setText(letter); mHandler.removeCallbacksAndMessages(null); mHandler.postDelayed(new Runnable() { @Override public void run() { tv_center.setVisibility(View.GONE); } }, 2000);}
5.进行排序展示
private void fillAndSortData(ArrayListpersons) { // 填充数据 for (int i = 0; i < Cheeses.NAMES.length; i++) { String name = Cheeses.NAMES[i]; persons.add(new Person(name)); } // 进行排序 Collections.sort(persons);}
Adapter中:
static class ViewHolder { TextView mIndex; TextView mName; public static ViewHolder getHolder(View view) { Object tag = view.getTag(); if(tag != null){ return (ViewHolder)tag; }else { ViewHolder viewHolder = new ViewHolder(); viewHolder.mIndex = (TextView) view.findViewById(R.id.tv_index); viewHolder.mName = (TextView) view.findViewById(R.id.tv_name); view.setTag(viewHolder); return viewHolder; } }
6.进行分组
ViewHolder mViewHolder = ViewHolder.getHolder(view); Person p = persons.get(position); String str = null; String currentLetter = p.getPinyin().charAt(0) + ""; // 根据上一个首字母,决定当前是否显示字母 if(position == 0){ str = currentLetter; }else { // 上一个人的拼音的首字母 String preLetter = persons.get(position - 1).getPinyin().charAt(0) + ""; if(!TextUtils.equals(preLetter, currentLetter)){ str = currentLetter; } } // 根据str是否为空,决定是否显示索引栏 mViewHolder.mIndex.setVisibility(str == null ? View.GONE : View.VISIBLE); mViewHolder.mIndex.setText(currentLetter); mViewHolder.mName.setText(p.getName()); return view;
7.将自定义控件和ListView结合起来
showLetter(letter); // 根据字母定位ListView, 找到集合中第一个以letter为拼音首字母的对象,得到索引 for (int i = 0; i < persons.size(); i++) { Person person = persons.get(i); String l = person.getPinyin().charAt(0) + ""; if(TextUtils.equals(letter, l)){ // 匹配成功 mMainList.setSelection(i); break; } }