前言:关于这个快速检索我们平常见到的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;
}
}
--------------------------------完整代码下载--------------------------