Android自定义控件之实现快速检索

前言:关于这个快速检索我们平常见到的app应用的很多,比如手机通讯录联系人、微信朋友,以及其他的商品列表等,实现的功能就是通过右侧或者左侧的字母进行快速检测,OK!今天我就带领大家来实现这个功能!

--------------------------------分割线--------------------------

首先看一下效果图:


--------------------------------分割线--------------------------

组成:1.右边是自定义QuickIndexBar(重点实现这个自定义控件);

2.左边是listview,它根据当前触摸的字母,去自己列表找首字母和触摸字母相同的那个item,然后让item放置到屏幕顶端(setSelection(position));

3.需要用到获取汉字的拼音,借助类库pinyin4j.jar实现;

4.动画效果,我们使用的是第三方jar包NineOldAndroid;

--------------------------------分割线--------------------------

一:实现自定义QuickIndexBar:

1.继承自View,实现里面的构造方法。

2.在init里面初始化画笔。

3.在onSizeChanged里面可以得到view的width,即可在onDraw里面绘制文本x坐标:width/2。

4.格子高度:view的总高度除以26个字母。

5.绘制文本y坐标:格子高度的一半 + 文本高度的一半 + position*格子高度。

6.计算触摸点对应的字母:根据触摸点的y坐标除以cellHeight,得到的值就是字母对应的索引。

7.当然了我们要设置一个接口,触摸字母的监听器,把触摸的字母回调给我们的监听者。

代码实现:

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

/**
 * Created by Fly on 2017/5/29.
 */

public class QuickIndexBar extends View {
    private String[] indexArr = {"A", "B", "C", "D", "E", "F", "G", "H",
            "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U",
            "V", "W", "X", "Y", "Z"};
    private Paint paint;
    private int width;
    private float cellHeight;

    public QuickIndexBar(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init();
    }

    public QuickIndexBar(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public QuickIndexBar(Context context) {
        super(context);
        init();
    }

    private void init() {
        paint = new Paint(Paint.ANTI_ALIAS_FLAG);//设置抗锯齿
        paint.setColor(Color.WHITE);
        paint.setTextSize(16);
        paint.setTextAlign(Paint.Align.CENTER);//设置文本的起点是文字边框底边的中心
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        width = getMeasuredWidth();
        //得到一个格子的高度
        cellHeight = getMeasuredHeight() * 1f / indexArr.length;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        for (int i = 0; i < indexArr.length; i++) {
            float x = width / 2;
            float y = cellHeight / 2 + getTextHeight(indexArr[i]) / 2 + i * cellHeight;
            paint.setColor(lastIndex == i ? Color.BLACK : Color.WHITE);
            canvas.drawText(indexArr[i], x, y, paint);
        }
    }

    private int lastIndex = -1;//记录上次的触摸字母的索引

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
            case MotionEvent.ACTION_MOVE:
                float y = event.getY();
                int index = (int) (y / cellHeight);//得到字母对应的索引
                if (lastIndex != index) {
                    //说明当前触摸字母和上一个不是同一个字母
//				Log.e("tag", indexArr[index]);
                    //对index做安全性的检查
                    if (index >= 0 && index < indexArr.length) {
                        if (listener != null) {
                            listener.onTouchLetter(indexArr[index]);
                        }
                    }
                }
                lastIndex = index;
                break;
            case MotionEvent.ACTION_UP:
                //重置lastIndex
                lastIndex = -1;
                break;
        }
        //引起重绘
        invalidate();
        return true;
    }

    /**
     * 获取文本的高度
     *
     * @param text
     * @return
     */
    private int getTextHeight(String text) {
        //获取文本的高度
        Rect bounds = new Rect();
        paint.getTextBounds(text, 0, text.length(), bounds);
        return bounds.height();
    }

    private OnTouchLetterListener listener;

    public void setOnTouchLetterListener(OnTouchLetterListener listener) {
        this.listener = listener;
    }

    /**
     * 触摸字母的监听器
     *
     * @author Administrator
     */
    public interface OnTouchLetterListener {
        void onTouchLetter(String letter);
    }

}
二:然后在MainActivity中设置Letter的监听:
quickIndexBar.setOnTouchLetterListener(new QuickIndexBar.OnTouchLetterListener() {
            @Override
            public void onTouchLetter(String letter) {
                //根据当前触摸的字母,去集合中找那个item的首字母和letter一样,然后将对应的item放到屏幕顶端
                for (int i = 0; i < friends.size(); i++) {
                    String firstWord = friends.get(i).getPinyin().charAt(0) + "";
                    if (letter.equals(firstWord)) {
                        //说明找到了,那么应该讲当前的item放到屏幕顶端
                        listview.setSelection(i);
                        break;//只需要找到第一个就行
                    }
                }

                //显示当前触摸的字母
                showCurrentWord(letter);
            }
        });
显示当前触摸的字母,这里我们可以加入动画效果,当然也可以在这里用handler进行延时隐藏文本(完整代码给出的有)。

protected void showCurrentWord(String letter) {
        currentWord.setText(letter);
        if (!isScale) {
            isScale = true;
            ViewPropertyAnimator.animate(currentWord).scaleX(1f)
                    .setInterpolator(new OvershootInterpolator())
                    .setDuration(450).start();
            ViewPropertyAnimator.animate(currentWord).scaleY(1f)
                    .setInterpolator(new OvershootInterpolator())
                    .setDuration(450).start();
        }

    }

三:关于如何文字转换成拼音。

实现思路:我们可以在ArrayList的泛型中定义name和pinyin两个字符串,然后在javaBean里完成name对拼音的转换。

JavaBean代码:

public class Friend implements Comparable<Friend>{
    private String name;
    private String pinyin;

    //使用成员变量生成构造方法:alt+shift+s->o
    public Friend(String name) {
        super();
        this.name = name;

        //一开始就转化好拼音
        setPinyin(PinYinUtil.getPinyin(name));
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public int compareTo(Friend another) {
        return getPinyin().compareTo(another.getPinyin());
    }

    public String getPinyin() {
        return pinyin;
    }

    public void setPinyin(String pinyin) {
        this.pinyin = pinyin;
    }

}
拼音工具类的实现是在第三方类库pinyin4j.jar的基础上进行封装,封装实现代码:
import android.text.TextUtils;
import net.sourceforge.pinyin4j.PinyinHelper;
import net.sourceforge.pinyin4j.format.HanyuPinyinCaseType;
import net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat;
import net.sourceforge.pinyin4j.format.HanyuPinyinToneType;
import net.sourceforge.pinyin4j.format.exception.BadHanyuPinyinOutputFormatCombination;

/**
 * Created by Fly on 2017/5/29.
 */

public class PinYinUtil {
    /**
     * 获取汉字的拼音,会销毁一定的资源,所以不应该被频繁调用
     * @param chinese
     * @return
     */
    public static String getPinyin(String chinese){
        if(TextUtils.isEmpty(chinese)) return null;

        //用来设置转化的拼音的大小写,或者声调
        HanyuPinyinOutputFormat format = new HanyuPinyinOutputFormat();
        format.setCaseType(HanyuPinyinCaseType.UPPERCASE);//设置转化的拼音是大写字母
        format.setToneType(HanyuPinyinToneType.WITHOUT_TONE);//设置转化的拼音不带声调

        //1.由于只能对单个汉字转化,所以需要将字符串转化为字符数组,然后对每个字符转化,最后拼接起来
        char[] charArray = chinese.toCharArray();
        String pinyin = "";
        for (int i = 0; i < charArray.length; i++) {
            //2.过滤空格
            if(Character.isWhitespace(charArray[i]))continue;

            //3.需要判断是否是汉字
            //汉字占2个字节,一个字节范围是-128~127,那么汉字肯定大于127
            if(charArray[i]>127){
                //可能是汉字
                try {
                    //由于多音字的存在,比如单  dan shan,
                    String[] pinyinArr = PinyinHelper.toHanyuPinyinStringArray(charArray[i],format);
                    if(pinyinArr!=null){
                        pinyin += pinyinArr[0];//此处即使有多音字,那么也只能取第一个拼音
                    }else {
                        //说明没有找到对应的拼音,汉字有问题,或者可能不是汉字,则忽略
                    }
                } catch (BadHanyuPinyinOutputFormatCombination e) {
                    e.printStackTrace();
                    //说明转化失败,不是汉字,比如O(∩_∩)O~,那么则忽略
                }
            }else {
                //肯定不是汉字,应该是键盘上能够直接输入的字符,这些字符能够排序,但不能获取拼音
                //所以可以直接拼接  a黑马->aheima
                pinyin += charArray[i];
            }
        }

        return pinyin;
    }
}
--------------------------------完整代码下载--------------------------

完整代码以及第三方类库pinyin4j.jar下载:Android自定义控件之实现快速检索代码

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

等待着冬天的风

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值