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 实现带字母索引的侧边栏功能,希望对大家有所帮助,如果大家有任何疑问,欢迎给我留言,小编会及时回复大家的!

以上是 Android 实现带字母索引的侧边栏功能 的全部内容, 来源链接: utcz.com/z/333511.html

回到顶部