仿小米通訊錄 右側滑動條與帶動畫的懸停列表實現(一)

先來看右側滑動條佈局

<com.reige.addressbook.IndexBar
        android:layout_alignParentRight="true"
        android:layout_width="20dp"
        android:layout_height="wrap_content"
        android:layout_marginTop="30dp"
        android:layout_marginBottom="30dp"/>

然後我們創建一個類繼承View來繪製右側字母導航滑動條

//初始化的方法
private void init() {
        //抗鋸齒
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        //設置繪製的文字大小
        mPaint.setTextSize(30);
        mPaint.setColor(Color.BLUE);
        //因爲默認的文字繪製錨點在文字的左下角,這樣會使文字的左邊在一條直線上 因爲字母的寬度不同會使繪製出的字母看上去比較亂 這個方法可以將錨點設置到文字底部中心 從而避免這個問題
        mPaint.setTextAlign(Paint.Align.CENTER);
    }

看上去比較亂

繪製簡單原理
這裏寫圖片描述

public class IndexBar extends View {

    private OnSlideListener onSlideListener;
    private String[] arr = {"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 int mWidth;
    private float mBoxHeight;

    public IndexBar(Context context) {
        super(context);

    }

    public IndexBar(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public IndexBar(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    private void init() {
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint.setTextSize(30);
        mPaint.setColor(Color.BLUE);
        //因爲默認的文字繪製錨點在文字的左下角,這樣會使文字的左邊在一條直線上 因爲字母的寬度不同會使繪製出的字母看上去比較亂 這個方法可以將錨點設置到文字底部中心 從而避免這個問題
        mPaint.setTextAlign(Paint.Align.CENTER);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mWidth = getMeasuredWidth();
        mBoxHeight = getMeasuredHeight() * 1f / arr.length;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        for (int i = 0; i < arr.length; i++) {
            float textHeight = getTextHeight(arr[i]);
            float x = mWidth / 2;
            float y = (1 + i) * mBoxHeight;
            mPaint.setColor(lastIndex==i?Color.RED:Color.BLUE);


            canvas.drawText(arr[i], x, y, mPaint);
        }
    }

    private int lastIndex = -1;

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
            case MotionEvent.ACTION_MOVE:

                float y = event.getY();
                //獲取當前點擊第幾個item
                int index = (int) (y / mBoxHeight);
                if (lastIndex != index) {
                    if (index >= 0 && index < arr.length) {
                        Log.e("index", "index:::" + index);

                        //選擇的letter變化 回調
                        if(onSlideListener!=null){
                            onSlideListener.onSlide(arr[index]);
                        }

                    }
                }
                lastIndex = index;
                break;
            case MotionEvent.ACTION_UP:
                lastIndex = -1;
                break;
        }

        invalidate();
        return true;
    }

    /**
     * @param text
     * @return 返回文字的高
     */
    private float getTextHeight(String text) {
        Rect rect = new Rect();
        mPaint.getTextBounds(text, 0, text.length(), rect);
        return rect.height();
    }

    /**
     * 設置監聽的方法
     */
    public interface OnSlideListener{
        void onSlide(String letter);
    }

    /**
     * 滑動監聽
     * @param osl
     */
    public void setOnSlideListener(OnSlideListener osl){
        this.onSlideListener = osl;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章