1用自定义布局画出来右边的索引栏
private String[] letterArr = {"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"};
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
for (int i = 0; i < letterArr.length; i++) {
String s = letterArr[i];
****这个是字体的高度****
int textHeight = getTextHeight(s);
**这个是把整个高度平分成26块**
cellHeight = getMeasuredHeight() * 1f / letterArr.length;
x = getMeasuredWidth() / 2;
**这里看图**
float y = cellHeight / 2 + textHeight / 2 + cellHeight * i;
**这个是设置点击后字体的效果index在此处的引用在后面有赋值,先不要看**
paint.setColor(index==i?pressColor:defColor);
canvas.drawText(s,x,y,paint);
}
}
private int getTextHeight(String s) {
Rect rect = new Rect();
**把字体的参数储存在矩形里面**
paint.getTextBounds(s,0,s.length(),rect);
return rect.height();
}
```
#2写触摸事件
```
private int index= -1;
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_MOVE:
**这里会出现问题点了之后字体回不到白色,就要保存一下按下的字母,手松开之后在让字母变回白色**
**获取 索引,每个字体的左边除以每层的高度再转化成int就是当前按下子母的坐标,保存一下,然后按下的index在上面的那一步设置按下的颜色黑色,**
int tempindex = (int) (event.getY() / cellHeight);
if (index != tempindex) {
index = tempindex;
if (index > -1 && index < letterArr.length) {
String letter = letterArr[index];
}
}
break;
**松开手,在让索引变回去**
case MotionEvent.ACTION_UP:
index = -1;
break;
}
**这里记得让重新刷新一下,**
invalidate();
return true;
}
3设置监听,将当前的按下的字母穿个activity
在按下和抬起里面设置这两个回调
public interface OnPressLetterListener {
**这个是按下去传的字母**
public void getLetter(String letter);
**这个是收抬起来的时候把收抬起的状态传过去**
public void release();
}
public void setOnPressLetterListener(OnPressLetterListener listener) {
this.listener = listener;
}
4从图片看这个activity是一个listView和quickindexbar组成的
4.1 findviewByid
4.2准备好我们要的数据bean并且排序
public class Friend implements Comparable<Friend>{
public String pinYin;
public String name;
public Friend(String name){
this.name = name;
this.pinYin = PinYinUtil.getPinYin(name);
}
@Override
public int compareTo(Friend friend) {
return this.pinYin.compareTo(friend.pinYin);
}
}
List<Friend> friends = new ArrayList<>();
Collections.sort(friends);
listview.setAdapter(new myAdapter());
4.2myAdapter
class myAdapter extends BaseAdapter {
private ViewHolder viewHolder;
@Override
public int getCount() {
return friends.size();
}
@Override
public Object getItem(int i) {
return null;
}
@Override
public long getItemId(int i) {
return 0;
}
@Override
public View getView(int i, View view, ViewGroup viewGroup) {
if (view == null) {
**这个布局是有连个部分组成的,一个字母一条数据,组成listview的一个条目**

view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.adapter_friend, null);
viewHolder = new ViewHolder(view);
view.setTag(viewHolder);
}else{
viewHolder = (ViewHolder) view.getTag();
}
Friend friend = friends.get(i);
viewHolder.tvName.setText(friend.name);
String letter = friend.pinYin.substring(0, 1);
if (i>0){
String preletter = friends.get(i - 1).pinYin.substring(0, 1);
**获取上一个条目的首字母比较是不是跟当前的一样,如果一样就隐藏当前首字母的那个布局**
if(letter.equals(preletter)){
viewHolder.tvLetter.setVisibility(View.GONE);
}else {
viewHolder.tvLetter.setVisibility(View.VISIBLE);
viewHolder.tvLetter.setText(letter);
}
}else {
viewHolder.tvLetter.setVisibility(View.VISIBLE);
viewHolder.tvLetter.setText(letter);
}
return view;
}
}
static class ViewHolder {
@InjectView(R.id.tv_letter)
TextView tvLetter;
@InjectView(R.id.tv_name)
TextView tvName;
ViewHolder(View view) {
ButterKnife.inject(this, view);
}
}
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/tv_letter"
android:text="A"
android:textColor="#fff"
android:background="#aa2b2b2b"
android:padding="15dp"
android:textSize="18sp"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/tv_name"
android:text="刘德华"
android:textColor="#111"
android:background="#fff"
android:padding="15dp"
android:textSize="18sp"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
4.4首字母的工具类
需要添加pinyin4j-2.5.0.jar
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);//不需要声调
//ps:由于不支持对多个汉字进行获取,所以要将字符串转为字符数组,对单个汉字进行获取
//最后,将每个字的拼音拼接起来,就是所有汉字的拼音
StringBuilder builder = new StringBuilder();
char[] chars = chinese.toCharArray();
for (int i = 0; i < chars.length; i++) {
char c = chars[i];
//1.要进行过滤空格,选择忽略
if(Character.isWhitespace(c)){
continue;
}
//2.要判断是否是中文,粗略的判断一下:由于一个汉字2个字节,
//一个字节范围是-128~127,因此汉字肯定大于127
if(c > 127){
//有可能是汉字,就利用pinyin4j进行获取
try {
//由于多音字的存在,所以返回的是数组,比如单:[chan, dan, shan]
String[] arr = PinyinHelper.toHanyuPinyinStringArray(c, format);
if(arr!=null){
//此处只能用第0个,原因:
//1.首先大部分汉字只有一个读音,多音字属于少数
//2.其次,我们也确实无能为力去判断应该用哪个,要判断一个汉字在一串文字
//中的精确读音,至少需要几个技术:a.分词算法 b.非常庞大的分词数据库
builder.append(arr[0]);
}
} catch (Exception e) {
e.printStackTrace();
//说明不是正确的汉字,选择忽略
}
}else {
//肯定不是汉字,一般是ASCII码表中的字母,对于这个情况,我们选择
//直接拼接
builder.append(c);
}
}
return builder.toString();
}
}
5设置回调的显示
quickIndexBar.setOnPressLetterListener(new QuickIndexBar.OnPressLetterListener() {
@Override
public void getLetter(String letter) {
for (int i = 0; i < friends.size(); i++) {
String substring = friends.get(i).pinYin.substring(0, 1);
**如果点的首字母跟传过来的一样,就让listview跳转到当前的首字母**
if (substring.equals(letter)) {
listview.setSelection(i);
break;
}
showTextView(letter);
}
}
@Override
public void release() {
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
textView.setVisibility(View.GONE);
}
},500);
}
});