需求来源

既然大家都做了快速索引,那我也来简单实现一下。
实现思路
-
分析元素和效果
有侧栏有27个字母中间一个隐藏TextView,点击和滑动变色并且显示当前字母,抬手后字母消失。 -
确定自定义属性
为了简单我这里就没有添加自定义属性,为了拓展和方便使用自己可以添加。 -
编写代码
3.1 定义相关变量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", "#"}; private int mItemHeight; private String mCurrentTouchWord; private Paint mPaint; private LetterTouchListener mListener; //构造方法中定义画笔 mPaint = new Paint(); mPaint.setAntiAlias(true); //sp要转成px mPaint.setTextSize(sp2px(12)); mPaint.setColor(Color.BLUE);
3.2 画字体(onDraw()中)
for (int i = 0; i < words.length; i++) { //根据每个字体的高度画 int letterCenterY = i * mItemHeight + mItemHeight / 2 + getPaddingTop(); Paint.FontMetrics fontMetrics = mPaint.getFontMetrics(); int dy = (int) ((fontMetrics.bottom - fontMetrics.top) / 2 - fontMetrics.bottom); int baseLine = letterCenterY + dy; int textWidth = (int) mPaint.measureText(words[i]); int x = getWidth() / 2 - textWidth / 2; //当前字母高亮(最好用两个画笔,因为mPaint.setColor是调用native方法) if (words[i].equals(mCurrentTouchWord)) { mPaint.setColor(Color.RED); canvas.drawText(words[i], x, baseLine, mPaint); } else { mPaint.setColor(Color.BLUE); canvas.drawText(words[i], x, baseLine, mPaint); } }
3.3 处理尺寸(onMeasure())
//计算宽度 = 左右的padding + 字母的宽度(取决画笔大小) int textWidth = (int) mPaint.measureText("A"); int width = getPaddingLeft() + getPaddingRight() + textWidth; int height = MeasureSpec.getSize(heightMeasureSpec); //去除padding mItemHeight = (getHeight() - getPaddingTop() - getPaddingBottom()) / words.length; setMeasuredDimension(width, height);
3.4 处理点击事件(onTouchEvent())
switch (event.getAction()) { //手指移动 case MotionEvent.ACTION_MOVE: float Y = event.getY(); //字母索引 int index = (int) (Y / mItemHeight); //由于getY可能是-100多等所以要做额外处理 if (index < 0) index = 0; if (index > words.length - 1) index = words.length - 1; if (!words[index].equals(mCurrentTouchWord)) { mCurrentTouchWord = words[index]; if (mListener != null) //定义触摸接口 mListener.touch(mCurrentTouchWord, true); //刷新界面 invalidate(); } break; //抬手动作 case MotionEvent.ACTION_UP: if (mListener != null) mListener.touch(mCurrentTouchWord, false); break; } //消费事件,事件分发机制单独会写一篇 return true;
3.5 接口
public interface LetterTouchListener { void touch(CharSequence letter, boolean isTouch); }
全部源码:
网友评论