快速索引 (对View的自定义)

快速索引 (对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;
                }
            }
上一篇:卸载Beta1后却不让安装Beta2的问题


下一篇:安装Visual Studio 2010出错解决方法总结