Android 实现带字母索引的侧边栏功能

时间:2022-07-27
本文章向大家介绍Android 实现带字母索引的侧边栏功能,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

之前已经用自定义View做出如下这样一个效果了

这两天需要重新拿来使用,发现效果虽然做出来了,不过思路不太对,就重新参考写了一个,用法也更为简单了

首要的自然是需要继承View绘制出侧边栏,并向外提供一个监听字母索引变化的方法

/**
* 作者:叶应是叶
* 时间:2017/8/20 11:38
* 描述:
*/
public class LetterIndexView extends View {
public interface OnTouchingLetterChangedListener {
void onHit(String letter);
void onCancel();
}
private OnTouchingLetterChangedListener touchingLetterChangedListener;
private Paint paint;
private boolean hit;
private final String[] letters = {"↑", "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 final int DEFAULT_WIDTH;
public LetterIndexView(Context context) {
this(context, null);
}
public LetterIndexView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public LetterIndexView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
paint = new Paint();
paint.setAntiAlias(true);
paint.setTextAlign(Paint.Align.CENTER);
paint.setColor(Color.parseColor("#565656"));
DEFAULT_WIDTH = dpToPx(context, 24);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(getWidthSize(widthMeasureSpec), getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
}
private int getWidthSize(int widthMeasureSpec) {
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
switch (widthMode) {
case MeasureSpec.AT_MOST: {
if (widthSize  = DEFAULT_WIDTH) {
return DEFAULT_WIDTH;
} else {
return widthSize;
}
}
case MeasureSpec.EXACTLY: {
return widthSize;
}
case MeasureSpec.UNSPECIFIED:
default:
return DEFAULT_WIDTH;
}
}
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
hit = true;
onHit(event.getY());
break;
case MotionEvent.ACTION_MOVE:
onHit(event.getY());
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
hit = false;
if (touchingLetterChangedListener != null) {
touchingLetterChangedListener.onCancel();
}
break;
}
invalidate();
return true;
}
@Override
protected void onDraw(Canvas canvas) {
if (hit) {
//字母索引条背景色
canvas.drawColor(Color.parseColor("#bababa"));
}
float letterHeight = ((float) getHeight()) / letters.length;
float width = getWidth();
float textSize = letterHeight * 5 / 7;
paint.setTextSize(textSize);
for (int i = 0; i < letters.length; i++) {
canvas.drawText(letters[i], width / 2, letterHeight * i + textSize, paint);
}
}
private void onHit(float offset) {
if (hit && touchingLetterChangedListener != null) {
int index = (int) (offset / getHeight() * letters.length);
index = Math.max(index, 0);
index = Math.min(index, letters.length - 1);
touchingLetterChangedListener.onHit(letters[index]);
}
}
public void setOnTouchingLetterChangedListener(OnTouchingLetterChangedListener onTouchingLetterChangedListener) {
this.touchingLetterChangedListener = onTouchingLetterChangedListener;
}
private int dpToPx(Context context, float dpValue) {
float scale = context.getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
}

在侧边栏时,中间会显示当前滑动指向的字母,这其实是一个TextView,在主布局文件中添加,通过IndexControl来控制TextView的可见性,并指示ListView滑动到指定项

/**
* 作者:叶应是叶
* 时间:2017/8/20 11:39
* 描述:
*/
public class IndexControl {
private final ListView listView;
private final TextView tv_hint;
private final Map<String, Integer  letterMap;
public IndexControl(ListView contactsListView, LetterIndexView letterIndexView,
TextView tv_hint, Map<String, Integer  letterMap) {
this.listView = contactsListView;
this.tv_hint = tv_hint;
this.letterMap = letterMap;
letterIndexView.setOnTouchingLetterChangedListener(new LetterChangedListener());
}
private class LetterChangedListener implements LetterIndexView.OnTouchingLetterChangedListener {
@Override
public void onHit(String letter) {
tv_hint.setVisibility(View.VISIBLE);
tv_hint.setText(letter);
int index = -1;
if ("↑".equals(letter)) {
index = 0;
} else if (letterMap.containsKey(letter)) {
index = letterMap.get(letter);
}
if (index < 0) {
return;
}
index += listView.getHeaderViewsCount();
if (index  = 0 && index < listView.getCount()) {
listView.setSelectionFromTop(index, 0);
}
}
@Override
public void onCancel() {
tv_hint.setVisibility(View.INVISIBLE);
}
}
}

这里也提供代码下载:LetterIndexView

总结

以上所述是小编给大家介绍的Android 实现带字母索引的侧边栏功能,希望对大家有所帮助,如果大家有任何疑问,欢迎给我留言,小编会及时回复大家的!