带索引栏的listview,在android开发非常普遍,方便用户进行字母索引,就像微信通讯录这样:

 玩转android自定义控件二——自定义索引栏listview_ide

  今天,我们就从零到一实现这个具有索引栏的listview.

  怎么实现这个控件了,我们应当梳理出一个思路。

  ①首先应当将字母的索引栏继承与一个控件,通过ondraw方法将字母画出来。

  ②然后我们应该监听这个字母控件的ontouch事件,来判断用户到底是按了那个字母。

  ③就是实现这个索引栏与listview的联动,就是将listview滑动到按下字母的位置。

  大体流程图如下:

 玩转android自定义控件二——自定义索引栏listview_ide_02

  有了前面铺垫,我们引出本文重头戏——代码。

  首先,索引栏这个控件如何将字母绘制在控件上的代码:

玩转android自定义控件二——自定义索引栏listview_ide_03

/**
* 侧边栏显示字母
*/
private String[] words = { "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) {
// TODO Auto-generated method stub
super.onDraw(canvas);
int height = getHeight();// 获取对应高度
int width = getWidth(); // 获取对应宽度
int singleHeight = height / words.length;// 获取每一个字母的高度
for (int i = 0; i < words.length; i++) {
paint.setColor(Color.rgb(33, 65, 98));
// paint.setColor(Color.WHITE);
paint.setTypeface(Typeface.DEFAULT_BOLD);
paint.setAntiAlias(true);
paint.setTextSize(20f);
// 选中的状态
if (isdown) {
paint.setColor(Color.parseColor("#ffffff"));
//paint.setFakeBoldText(true);
}
// x坐标等于中间-字符串宽度的一半.
float xPos = width / 2 - paint.measureText(words[i]) / 2;
float yPos = singleHeight * i + singleHeight;
canvas.drawText(words[i], xPos, yPos, paint);
paint.reset();// 重置画笔
}
}

玩转android自定义控件二——自定义索引栏listview_ide_03

  通过上述的代码,我们可以得出以下的结论:将要绘制的字母以从上到下的顺序绘制在一个指定区域,每个字母的x坐标是一样的,x坐标即为控件宽度一半。如果当前字母选中的话,就高亮显示。思路如图所示:

玩转android自定义控件二——自定义索引栏listview_控件_05

  紧接着,就来到第二步,确定用户到底点击是那个字母,代码如下:

玩转android自定义控件二——自定义索引栏listview_ide_03

/**
* 处理触摸事件的方法
* 用户按下时候,整个控件背景变化
* 根据按下y坐标 判断究竟用户按下那个字母
* 当前字母高亮显示 将其字母显示listview中央
*/
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
int action = event.getAction();
final float y = event.getY();// 点击y坐标
final int oldChoose = choose;
final ITouchingLetterChangedListener listener = onTouchingLetterChangedListener;
final int c = (int) (y / getHeight() * words.length);// 点击y坐标所占总高度的比例*b数组的长度就等于点击b中的个数.
switch (action) {
case MotionEvent.ACTION_UP:
isdown=false;
setBackgroundResource(android.R.color.transparent);
choose = -1;//
invalidate();
if (textViewDialog != null) {
textViewDialog.setVisibility(View.INVISIBLE);
}
break;
default:
isdown=true;
setBackgroundResource(R.color.sidebar_bg_color);
if (oldChoose != c) {
if (c >= 0 && c < words.length) {
if (listener != null) {
listener.OnTouchingLetterChanged(words[c]);
}
if (textViewDialog != null) {
textViewDialog.setText(words[c]);
textViewDialog.setVisibility(View.VISIBLE);
}
choose = c;
invalidate();
}
}
break;
}
return true;
}

玩转android自定义控件二——自定义索引栏listview_ide_03

  通过上述的代码,我们可以这样总结:当用户按下的时候,整个控件背景发生变化,根据用户按下的y坐标来确定用户究竟是按下那个字母,并且将按下字母显示屏幕的中央,效果图如下:

玩转android自定义控件二——自定义索引栏listview_控件_08

  最终,将listview 移动到按下字母相应位置,代码如下:

玩转android自定义控件二——自定义索引栏listview_ide_03

/**
* 根据用户点击那个字母将listview移动到相应位置
*/
sidebar.setOnTouchingLetterChangedListener(new ITouchingLetterChangedListener() {
@Override
public void OnTouchingLetterChanged(String cString) {
int position = -1;
if (cString.length() > 0) {
position = myAdapter.getPositionForSection(cString
.charAt(0));
}
if (position != -1) {
listview.setSelection(position);
} else if (cString.contains("#")) {
listview.setSelection(0);
}
}
});

玩转android自定义控件二——自定义索引栏listview_ide_03

  连篇累牍说了这么多,控件大功告成的效果为:

玩转android自定义控件二——自定义索引栏listview_高亮显示_11

  源代码地址为:

​  http://pan.baidu.com/s/1dDMDjhR​