自定义控件之字母索引

分析:这是一个很常见的功能,类似微信通录,实现方式也比较简单,先是用画笔画确定文字的中心位置,然后计算出出文字的宽度,接着遍历26个字母。最后通过onTouchEvent事件,获取坐标Y值,从而确定选中字母,最后高亮字母,invalidate()方法绘制。关键一点就是在onMeasure中重新计算控件的宽度,还有就是要防止选中下标超出范围,具体实现如下:

/**
 * Email [email protected]
 * Created by Michael Chen on 2018/6/3.
 * Version 1.0
 * Description:字母索引练习
 */
public class LetterSideBar extends View {
    //定义26个字母
    public static String[] mLetters = {"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 Paint mPaint;
    //当前触摸的位置字母
    private String mCurrentLetter="A";
    private String mCurrentTouchListener;
    private int cellHeight;

    public LetterSideBar(Context context) {
        this(context,null);
    }

    public LetterSideBar(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs,0);
    }

    public LetterSideBar(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mPaint=new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setTextSize(sp2px(12));
        mPaint.setColor(Color.BLUE);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        //计算指定宽度=左右的padding+字母的宽度
        int textWidth= (int) mPaint.measureText("A");
        int width=getPaddingLeft()+getPaddingRight()+textWidth;
        //高度可以直接获取
        int height = MeasureSpec.getSize(heightMeasureSpec);
        setMeasuredDimension(width,height);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //画26个字母
        cellHeight = (getHeight() - getPaddingBottom() - getPaddingTop()) / mLetters.length;
        for (int i = 0; i < mLetters.length; i++) {
            //当前的letterCenterY是cellHeight/2+之前所有单元格的高度
            int letterCenterY=getPaddingTop()+i* cellHeight + cellHeight /2;
            //计算基线
            Paint.FontMetrics fontMetrics = mPaint.getFontMetrics();
            int dy= (int) ((fontMetrics.bottom-fontMetrics.top)/2-fontMetrics.bottom);
            int baseLine=letterCenterY+dy;
            int textWidth= (int) mPaint.measureText(mLetters[i]);
            //x的左下标为控件宽度/2-文字宽度/2;
            int x=getWidth()/2-textWidth/2;
            //当前字母高亮
            if (mCurrentLetter.equals(mLetters[i])){
                mPaint.setColor(Color.RED);
                canvas.drawText(mLetters[i],x,baseLine,mPaint);
            }else {
                mPaint.setColor(Color.BLUE);
                canvas.drawText(mLetters[i], x, baseLine, mPaint);
            }
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()){
            case MotionEvent.ACTION_DOWN:
            case MotionEvent.ACTION_MOVE:
                //当前触摸位置,计算选中的字母
                float currentY=event.getY();
                //位置=currentY/单元格高度
               int currentPosition= (int) (currentY/cellHeight);
               if (currentPosition<=0){
                   currentPosition=0;
               }
               if (currentPosition>=mLetters.length-1){
                   currentPosition=mLetters.length-1;
               }
               mCurrentLetter=mLetters[currentPosition];
                if(mListener!=null){
                    mListener.touch(mCurrentLetter,false);
                }
               invalidate();
                break;
            case MotionEvent.ACTION_UP:
                if(mListener!=null){
                    mListener.touch(mCurrentLetter,false);
                }
                break;
        }
        return true;
    }
    // sp 转 px
    private float sp2px(int sp) {
        return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,
                sp, getResources().getDisplayMetrics());
    }
    private LetterTouchListener mListener;
    public interface LetterTouchListener{
        void touch(String letter,boolean isTouch);
    }
}

你可能感兴趣的:(自定义控件之字母索引)