Android 實(shí)現(xiàn)帶字母索引的側(cè)邊欄功能
之前已經(jīng)用自定義View做出如下這樣一個(gè)效果了

這兩天需要重新拿來使用,發(fā)現(xiàn)效果雖然做出來了,不過思路不太對(duì),就重新參考寫了一個(gè),用法也更為簡單了
首要的自然是需要繼承View繪制出側(cè)邊欄,并向外提供一個(gè)監(jiān)聽字母索引變化的方法
/**
* 作者:葉應(yīng)是葉
* 時(shí)間: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);
}
}
在側(cè)邊欄時(shí),中間會(huì)顯示當(dāng)前滑動(dòng)指向的字母,這其實(shí)是一個(gè)TextView,在主布局文件中添加,通過IndexControl來控制TextView的可見性,并指示ListView滑動(dòng)到指定項(xiàng)
/**
* 作者:葉應(yīng)是葉
* 時(shí)間: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
總結(jié)
以上所述是小編給大家介紹的Android 實(shí)現(xiàn)帶字母索引的側(cè)邊欄功能,希望對(duì)大家有所幫助,如果大家有任何疑問,歡迎給我留言,小編會(huì)及時(shí)回復(fù)大家的!
相關(guān)文章
深入解析Android中的setContentView加載布局原理
在日常開發(fā)Android中setContentView是必不可少的一部分,下面這篇文章主要給大家介紹了關(guān)于Android中setContentView的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)下吧。2017-09-09
android listview進(jìn)階實(shí)例分享
這篇文章主要介紹了android listview進(jìn)階實(shí)例分享,具有一定借鑒價(jià)值,需要的朋友可以參考下2018-01-01
Android中SQLite數(shù)據(jù)庫知識(shí)點(diǎn)總結(jié)
在本篇文章里小編給大家分享了關(guān)于Android中SQLite數(shù)據(jù)庫知識(shí)點(diǎn)總結(jié),有需要的朋友們跟著學(xué)習(xí)下。2019-02-02
Android提高之TelephonyManager功能探秘
這篇文章主要介紹了Android的TelephonyManager功能,可以幫助讀者更好的理解Java反射機(jī)制,需要的朋友可以參考下2014-08-08
Android 滑動(dòng)小圓點(diǎn)ViewPager的兩種設(shè)置方法詳解流程
Viewpager,視圖翻頁工具,提供了多頁面切換的效果。Android 3.0后引入的一個(gè)UI控件,位于v4包中。低版本使用需要導(dǎo)入v4包,現(xiàn)在我們一般不再兼容3.0及以下版本,另外使用Android studio開發(fā),默認(rèn)導(dǎo)入v7包,v7包含了v4,所以不用導(dǎo)包,越來越方便了2021-11-11
Android報(bào)錯(cuò)Error:Could not find com.android.tools.build:gradle
這篇文章主要介紹了Android Studio報(bào)錯(cuò)Error:Could not find com.android.tools.build:gradle:4.1解決辦法,碰到該問題的同學(xué)快過來看看吧2021-08-08
基于Flutter實(shí)現(xiàn)手勢(shì)密碼加密與解鎖功能
這篇文章主要介紹了如何利用Flutter實(shí)現(xiàn)手勢(shì)密碼的加密與解鎖,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-04-04
Android實(shí)現(xiàn)類似iOS風(fēng)格的對(duì)話框?qū)嵗a
通過本文給大家分享一個(gè)簡單的常用的對(duì)話框類,關(guān)于Android實(shí)現(xiàn)類似iOS風(fēng)格的對(duì)話框?qū)嵗a大家通過本文學(xué)習(xí)下吧2017-09-09

