快速索引 (对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;
@Override
public 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.jar

public 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(ArrayList<Person> persons) {
// 填充数据
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;
}
}

快速索引 (对View的自定义)的更多相关文章

  1. Android ListView A~Z快速索引(改进版)

    上一篇文章虽然实现了ListView 快速索引的效果,但是有一个小小的Bug.这个Bug我在前面也说了,这篇文章就来解决这个Bug. 我研究的时候发现只要showBg值为true,中间的字母就显示,而 ...

  2. 实现ListView A~Z快速索引

    ListView A~Z快速索引这种效果在通信录和城市列表中经常看到,方便用户查找,是一种增加用户体验的好方法. 实现步骤: 1.自定义一个名叫SlideBar 的View. 2.在布局文件中加入这个 ...

  3. Android-自定义联系人快速索引

    效果图: 布局去指定 view.custom.shangguigucustomview.MyCustomIndexView 自定义View对象 <!-- 自定义联系人快速索引 --> &l ...

  4. 8.快速索引、listview

    实现这样的效果 布局: <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" ...

  5. Log4net快速索引参考

    官方项目地址:The Apache log4net project 本文内容仅为相关项参考,不进行具体使用讨论 另转载请注明出处 Log4net快速索引参考 Log4net主要有以下三个部件: log ...

  6. Dialog详解(包括进度条、PopupWindow、自定义view、自定义样式的对话框)

    Dialog详解(包括进度条.PopupWindow.自定义view.自定义样式的对话框)   Android中提供了多种对话框,在实际应用中我们可能会需要修改这些已有的对话框.本实例就是从实际出发, ...

  7. Android 快速索引(城市列表和联系人)

    最近需要实现一个城市列表的快速索引功能.类似于联系人应用,根据姓名首字母快速索引功能. 要实现这个功能只需要解决两个问题:1.对列表进行分组(具有同一特征),并且能够快速定位到该组的第一项 2.右侧分 ...

  8. 通过圆形载入View了解自定义View

    这是自定义View的第一篇文章,通过制作简单的自定义View来了解自定义View的流程. 自定义View是Android学习和开发中必不可少的一部分.通过自定义View我们可以制作丰富绚丽的控件,自定 ...

  9. 【大盛】HTC one/M7 ROM 最新本地化OrDroid8.2.6 高级、快速设置 永久root 更多自定义 稳定 流畅

    了解更多:点击下载ROM和学习更多 ROM版本 HTC-one_OrDroid8.2.6 ROM作者 雪狼团队·大盛 http://weibo.com/DaShengdd Android版本 Andr ...

随机推荐

  1. jstl标签库示例二

    package app05b;import java.io.IOException;import java.util.HashMap;import java.util.Map;import javax ...

  2. [SCOI2008]城堡

    题目描述 在一个国家里,有n个城市(编号为0 到n-1).这些城市之间有n条双向道 路相连(编号为0 到n-1),其中编号为i的道路连接了城市i和城市ri(一条道 路可以连接一个城市和它自身),长度为 ...

  3. Codeforces Round #460 E. Congruence Equation

    Description 题面 \(n*a^n≡b (\mod P),1<=n<=x\) Solution 令 \(n=(P-1)*i+j\) \([(P-1)*i+j]*a^{[(P-1) ...

  4. [洛谷]P3613 睡觉困难综合征

    题目大意:给出一棵n个点的树,每个点有一个运算符(与.或.异或)和一个数,支持两种操作,第一种修改一个点的运算符和数,第二种给出x,y,z,询问若有一个0~z之间的数从点x走到点y(简单路径),并且对 ...

  5. 17.10.28&29

    28上午 骚猪选讲 28下午 BOZJ 1081 [SCOI2005]超级格雷码 感觉就是一个找规律,然后模拟输出.半天没找到一个比较简便的模拟方法,这份代码是学习网上一位大佬的,很巧妙. 代码: # ...

  6. 中断下半部处理之tasklet

    1.tasklet概述 下半部和退后执行的工作,软中断的使用只在那些执行频率很高和连续性要求很高的情况下才需要.在大多数情况下,为了控制一个寻常的硬件设备,tasklet机制都是实现自己下半部的最佳选 ...

  7. hdu 5445 多重背包

    Food Problem Time Limit: 3000/2000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)To ...

  8. 用Qemu运行/调试arm linux【转】

    转自:https://blog.csdn.net/absurd/article/details/78984244 用Qemu运行/调试arm linux,这事情干过好几次了,久了就忘记了,每次都要重新 ...

  9. Spring源码分析(一)--BeanProcessor

    一.何谓BeanProcessor BeanProcessor是SpringFramework里非常重要的核心接口之一,我先贴出一段源代码: /* * Copyright 2002-2015 the ...

  10. python nonloacal

    Python 3 添加了 nonlocal 关键字,把 None.True 和 False 提升为关键字,废弃了 print 和 exec.今天细说下 nonlocal 的用法 nonloacal是最 ...