自定義View之身高選擇器

 自定義View畫一個身高測量尺子,能夠理解成一個豎着的尺子java

最近恰好有空,在家裏整理這幾年工做內容,簡單記錄一下,也方便之後本身查閱,最終效果圖以下android

步驟以下:git

首先仍是繼承view,重寫onMeasure()方法github

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        setMeasuredDimension(measureWidth(widthMeasureSpec), measureHeight(heightMeasureSpec));
    }

    /**
     * 測量控件所需寬度
     */
    public int measureWidth(int widthMeasureSpec) {
        switch (MeasureSpec.getMode(widthMeasureSpec)) {
            case MeasureSpec.AT_MOST:
            case MeasureSpec.UNSPECIFIED: {
                switch (mOrientation) {
                    case HORIZONTAL: {
                        return mLines * space;
                    }
                    case VERTICAL:
                    default: {
                        float textWidth = mTextPaint.measureText(String.valueOf(mLines / mSetupValue));
                        float width = textWidth + mLongLineLength + mMarkerWidth + mMarkerSpace + getPaddingLeft() + getPaddingRight();
                        return (int) width;
                    }
                }
            }
            case MeasureSpec.EXACTLY:
            default:
                return MeasureSpec.getSize(widthMeasureSpec);
        }

    }

    /**
     * 測量控件所需高度
     */
    public int measureHeight(int heightMeasureSpec) {
        switch (MeasureSpec.getMode(heightMeasureSpec)) {
            case MeasureSpec.AT_MOST:
            case MeasureSpec.UNSPECIFIED: {
                switch (mOrientation) {
                    case HORIZONTAL: {
                        float height = mTextPaint.getTextSize() + mLongLineLength + mMarkerWidth + mMarkerSpace + getPaddingTop() + getPaddingBottom();
                        return (int) height;
                    }
                    case VERTICAL:
                    default: {
                        return mLines * space;
                    }
                }
            }
            case MeasureSpec.EXACTLY:
            default:
                return MeasureSpec.getSize(heightMeasureSpec);
        }
    }

 

 

第二步會在onDraw()方法中繪製當前View,此時繪製的view也是初始時的viewcanvas

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        adjustMarker(false);
        canvas.drawColor(mBackgroundColor);
        switch (mOrientation) {
            case VERTICAL:
                drawVertical(canvas);
                break;
            case HORIZONTAL:
                drawHorizontal(canvas);
                break;
        }
    }

 

默認狀況下不會調整標記view的位置。固然標記的位置能夠時固定的,也能夠不固定的,固定的話就是滾動尺子的位置數組

畫圖的時候,先畫紅色標尺的位置,而後畫刻度的位置,刻度的位置每10個畫一根長線,就是每10個分爲1組,具體代碼以下:app

 

    /**
     * 繪製 方向爲垂直方向時的佈局
     *
     * @param canvas 畫布
     */
    protected void drawVertical(Canvas canvas) {
        //vertical mode
        // bottom start position
        int bottom = getHeight() - getPaddingBottom();
        int left = getPaddingLeft();

        float maxTextWidth = mTextPaint.measureText(String.valueOf((mLines+mStartLineValue) / mOutSideLine * mSetupValue));

        int shakeCenter = (getHeight() >> 1) + getScrollY();
        resetLinesArr();

        for (int i = 0; i <= mLines; i++) {
            int value = mStartLineValue + (i * mSetupValue);
            float lineLength;
            switch (i % mOutSideLine) {
                case ZERO:
                    String text = String.valueOf(value);
                    float currentTextWidth = mTextPaint.measureText(text);
                    canvas.drawText(text, left + (maxTextWidth - currentTextWidth) / 2, bottom - i * space, mTextPaint);
                    lineLength = mLongLineLength;
                    break;
                default:
                    lineLength = mShortLineLength;
                    break;
            }
            mLinesArr[i * 4] = left + maxTextWidth;
            mLinesArr[i * 4 + 1] = bottom - i * space;
            mLinesArr[i * 4 + 2] = left + maxTextWidth + lineLength;
            mLinesArr[i * 4 + 3] = bottom - i * space;
        }

        //繪製線
        canvas.drawLines(mLinesArr, mPaint);
        //繪製高亮線
        canvas.drawLine(left + maxTextWidth,
                bottom - mCurrentLineIndex * space,
                left + maxTextWidth + (((mCurrentLineIndex) % mOutSideLine == 0) ? mLongLineLength : mShortLineLength),
                bottom - mCurrentLineIndex * space,
                mHighlightPaint);
    }

 

 

第三個比較重要的是觸摸事件,每一次向上或者向下都要重繪刷新當前Viewide

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction() & MotionEvent.ACTION_MASK) {
            case MotionEvent.ACTION_DOWN:
                if (!mOverScroller.isFinished()) mOverScroller.abortAnimation();
                //adjustMarker(true);
                break;
            case MotionEvent.ACTION_MOVE:
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                adjustMarker(true);
                break;
        }
        mGestureDetector.onTouchEvent(event);
        return true;
    }

 

 

全部具體代碼以下:佈局

 

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.support.v4.view.ViewCompat;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;


import com.bingo.customer.R;

import java.util.Arrays;

/**
 * 身高體重測量控件
 * 這個控件是爲了項目中的身高體重選擇而設計編碼的
 * 不適合多數據狀況,由於沒有使用任何的回收機制
 *
 */
public class HeightView extends View {

    /**
     * 水平方向
     */
    public static final int HORIZONTAL = 1;
    /**
     * 垂直方向
     */
    public static final int VERTICAL = 2;

    public static final int ZERO = 0;

    /**
     * 默認的阻尼係數
     */
    public static final float DEFAULT_RATIO = 2.0f;

    private static final String TAG = "HeightView";
    /**
     * 阻尼係數,在fling下的阻力,阻力越大就飛的就約慢
     */
    private float ratio = DEFAULT_RATIO;


    /**
     * 須要繪製多少行
     */
    private int mLines = 240;
    /**
     * 突出行 就是長線 那一行
     */
    private int mOutSideLine = 10;
    /**
     * 每一個outSideLine的步進值
     * 好比:
     * 步進值是 5 那麼就是  0,5,10,15,20
     * 步進值是 10 那麼就是 0,10,20,30,40
     */
    private int mSetupValue = 1;


    /**
     * 每一個格子的間距
     */
    private int space;
    /**
     * 用於普通繪製的畫筆
     */
    private Paint mPaint;
    /**
     * 繪製文本的畫筆
     */
    private Paint mTextPaint;
    /**
     * 短線的長度
     */
    private float mShortLineLength;
    /**
     * 長線的長度
     */
    private float mLongLineLength;
    /**
     * 高亮畫筆,繪製選中線的
     */
    private Paint mHighlightPaint;

    /**
     * Marker畫筆
     */
    private Paint mMarkerPaint;

    /**
     * scroller 用於滾動的輔助類
     */
    private OverScroller mOverScroller;
    /**
     * 手勢探測器 用於探測手勢
     */
    private GestureDetector mGestureDetector;
    /**
     * 高亮色選擇中的顏色
     */
    private int mHighLightColor;
    /**
     * 文本顏色
     */
    private int mTextColor;
    /**
     * 文本大小
     */
    private float mTextSize;
    /**
     * 高亮的線的寬度
     */
    private float mHighlightWidth;
    /**
     * 普通的線的寬度
     */
    private float mLineWidth;

    /**
     * 線條的顏色
     */
    private int mLineColor;

    /**
     * 上一次是不是fling模式
     */
    private boolean mPreviousIsFling = false;

    /**
     * 開始行
     * 若是開始行爲 0,步進值爲10
     * 則 0,10,20,30,40
     * 若是開始行爲 10,步進值爲10
     * 則 100,110,120,130
     */
    private int mStartLineValue = 0;

    /**
     * 用於記錄當前的marker的位置
     */
    private int mCurrentLineIndex;

    /**
     * 保存線位置的數組
     */
    private float[] mLinesArr = new float[4];

    /**
     * 重力方向
     */
    private int mOrientation = VERTICAL;

    /**
     * 指示器的寬度
     */
    private int mMarkerWidth = 45;

    /**
     * 指示器和長線的距離
     */
    private int mMarkerSpace = 20;

    /**
     * 背景色
     */
    private int mBackgroundColor = Color.parseColor("#03b7ee");

    /**
     * 標記物路徑
     */
    private Path mMarkerPath;
    /**
     * Marker顏色
     */
    private int mMarkerColor;

    private OnItemChangedListener mOnItemChangedListener;


    public HeightView(Context context) {
        super(context);
        init();
    }

    public HeightView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public HeightView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
        if (attrs != null) {
            TypedArray attributes = context.obtainStyledAttributes(attrs, R.styleable.HeightView, defStyleAttr, 0);
            mOrientation = attributes.getInt(R.styleable.HeightView_orientation, VERTICAL);
            mBackgroundColor = attributes.getColor(R.styleable.HeightView_backgroundColor, mBackgroundColor);
            mTextColor = attributes.getColor(R.styleable.HeightView_textColor, mTextColor);
            mTextPaint.setColor(mTextColor);
            mTextSize = attributes.getDimension(R.styleable.HeightView_textSize, mTextSize);
            mTextPaint.setTextSize(mTextSize);

            mHighLightColor = attributes.getColor(R.styleable.HeightView_highlightColor, mHighLightColor);
            mHighlightPaint.setColor(mHighLightColor);
            mHighlightWidth = attributes.getDimension(R.styleable.HeightView_highlightLineWidth, mHighlightWidth);
            mHighlightPaint.setStrokeWidth(mHighlightWidth);

            mMarkerColor = attributes.getColor(R.styleable.HeightView_markerColor, mMarkerColor);
            mMarkerPaint.setColor(mMarkerColor);

            mLineColor = attributes.getColor(R.styleable.HeightView_mlineColor, mLineColor);
            mPaint.setColor(mLineColor);

            mLineWidth = attributes.getDimension(R.styleable.HeightView_lineWidth, mLineWidth);
            mPaint.setStrokeWidth(mLineWidth);

            ratio = attributes.getFloat(R.styleable.HeightView_ratio, ratio);
            mMarkerSpace = attributes.getDimensionPixelOffset(R.styleable.HeightView_markerSpace, mMarkerSpace);

            mLines = attributes.getInt(R.styleable.HeightView_lines, mLines);
            mStartLineValue = attributes.getInt(R.styleable.HeightView_startLineValue, mStartLineValue);

            mMarkerWidth = attributes.getDimensionPixelOffset(R.styleable.HeightView_markerSize, mMarkerWidth);

            attributes.recycle();
        }
    }


    /**
     * 初始化所需條件
     */
    private void init() {
        setLayerType(LAYER_TYPE_HARDWARE, null);

        space = (int) (getResources().getDisplayMetrics().density * 7);
        mHighLightColor = Color.parseColor("#1e7d9e");

        mTextColor = mMarkerColor = Color.WHITE;

        mTextSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 12, getResources().getDisplayMetrics());
        mShortLineLength = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 12, getResources().getDisplayMetrics());
        mLongLineLength = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 30, getResources().getDisplayMetrics());
        mHighlightWidth = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 1.5f, getResources().getDisplayMetrics());
        mLineWidth = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 1, getResources().getDisplayMetrics());

        mMarkerPath = new Path();

        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setColor(mLineColor = Color.WHITE);
        mPaint.setStrokeWidth(mLineWidth);

        mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mTextPaint.setTextSize(mTextSize);
        mTextPaint.setStyle(Paint.Style.FILL);
        mTextPaint.setColor(mTextColor);
        mTextPaint.setTextAlign(Paint.Align.CENTER);

        mHighlightPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mHighlightPaint.setStyle(Paint.Style.STROKE);
        mHighlightPaint.setColor(mHighLightColor);
        mHighlightPaint.setStrokeWidth(mHighlightWidth);

        mMarkerPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mHighlightPaint.setStyle(Paint.Style.FILL);
        mHighlightPaint.setColor(mMarkerColor);


        mOverScroller = new OverScroller(getContext());

        mGestureDetector = new GestureDetector(getContext(), new GestureDetector.SimpleOnGestureListener() {
            @Override
            public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
                switch (mOrientation) {
                    case VERTICAL: {
                        //往上滾動
                        if (distanceY > 0) {
                            //最大滾動到Marker位置
                            int distance = (getHeight() >> 1) - getPaddingBottom()/* - (mStartLineValue) * space*/;
                            if (getScrollY() + distanceY > distance) {
                                scrollTo(0, distance);
                                ViewCompat.postInvalidateOnAnimation(HeightView.this);
                            } else if (getScrollY() + distanceY < distance) {
                                scrollBy(0, (int) distanceY);
                                ViewCompat.postInvalidateOnAnimation(HeightView.this);
                            }
                            //往下滾動
                        } else if (distanceY < 0) {
                            int minDistance = (mLines * space - (getHeight() >> 1)) + getPaddingBottom();
                            if (getScrollY() < -minDistance) {
                                scrollTo(0, -minDistance);
                                ViewCompat.postInvalidateOnAnimation(HeightView.this);
                            } else if (getScrollY() > -minDistance) {
                                scrollBy(0, (int) distanceY);
                                ViewCompat.postInvalidateOnAnimation(HeightView.this);
                            }
                        }
                    }
                    break;
                    case HORIZONTAL: {
                        //往左滾動
                        if (distanceX > 0) {
                            int maxX = (mLines /*+ mStartLineValue*/) * space - (getWidth() >> 1) + getPaddingLeft();
                            if (getScrollX() + distanceX > maxX) {
                                scrollTo(maxX, 0);
                                ViewCompat.postInvalidateOnAnimation(HeightView.this);
                            } else if (getScrollX() + distanceX <= maxX) {
                                scrollBy((int) distanceX, 0);
                                ViewCompat.postInvalidateOnAnimation(HeightView.this);
                            }
                            //往右滾動
                        } else if (distanceX < 0) {
                            int minX = -((getWidth() >> 1) - getPaddingLeft());
                            if (getScrollX() + distanceX < minX) {
                                scrollTo(minX, 0);
                                ViewCompat.postInvalidateOnAnimation(HeightView.this);
                            } else if (getScrollX() + distanceX >= minX) {
                                scrollBy((int) distanceX, 0);
                                ViewCompat.postInvalidateOnAnimation(HeightView.this);
                            }
                        }
                    }
                    break;
                }

                return true;
            }

            @Override
            public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
                switch (mOrientation) {
                    case VERTICAL: {
                        int minDistance = ((mLines) * space - (getHeight() >> 1)) + getPaddingBottom();
                        int maxDistance = (getHeight() >> 1) - getPaddingBottom();
                        mOverScroller.fling(0, getScrollY(), 0, (int) (-velocityY / ratio), 0, 0, -minDistance, maxDistance, 0, 100);
                    }
                    break;
                    case HORIZONTAL: {
                        int minX = -((getWidth() >> 1) - getPaddingLeft());
                        int maxX = (mLines /*+ mStartLineValue*/) * space - (getWidth() >> 1) + getPaddingLeft();
                        mOverScroller.fling(getScrollX(), 0, (int) (-velocityX / ratio), 0, minX, maxX, 0, 0, 100, 0);
                    }
                    break;
                }
                ViewCompat.postInvalidateOnAnimation(HeightView.this);
                return true;
            }
        });
    }


    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        setMeasuredDimension(measureWidth(widthMeasureSpec), measureHeight(heightMeasureSpec));
    }

    /**
     * 測量控件所需寬度
     */
    public int measureWidth(int widthMeasureSpec) {
        switch (MeasureSpec.getMode(widthMeasureSpec)) {
            case MeasureSpec.AT_MOST:
            case MeasureSpec.UNSPECIFIED: {
                switch (mOrientation) {
                    case HORIZONTAL: {
                        return mLines * space;
                    }
                    case VERTICAL:
                    default: {
                        float textWidth = mTextPaint.measureText(String.valueOf(mLines / mSetupValue));
                        float width = textWidth + mLongLineLength + mMarkerWidth + mMarkerSpace + getPaddingLeft() + getPaddingRight();
                        return (int) width;
                    }
                }
            }
            case MeasureSpec.EXACTLY:
            default:
                return MeasureSpec.getSize(widthMeasureSpec);
        }

    }

    /**
     * 測量控件所需高度
     */
    public int measureHeight(int heightMeasureSpec) {
        switch (MeasureSpec.getMode(heightMeasureSpec)) {
            case MeasureSpec.AT_MOST:
            case MeasureSpec.UNSPECIFIED: {
                switch (mOrientation) {
                    case HORIZONTAL: {
                        float height = mTextPaint.getTextSize() + mLongLineLength + mMarkerWidth + mMarkerSpace + getPaddingTop() + getPaddingBottom();
                        return (int) height;
                    }
                    case VERTICAL:
                    default: {
                        return mLines * space;
                    }
                }
            }
            case MeasureSpec.EXACTLY:
            default:
                return MeasureSpec.getSize(heightMeasureSpec);
        }
    }


    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction() & MotionEvent.ACTION_MASK) {
            case MotionEvent.ACTION_DOWN:
                if (!mOverScroller.isFinished()) mOverScroller.abortAnimation();
                //adjustMarker(true);
                break;
            case MotionEvent.ACTION_MOVE:
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                adjustMarker(true);
                break;
        }
        mGestureDetector.onTouchEvent(event);
        return true;
    }

    @Override
    public boolean performClick() {
        return super.performClick();
    }

    /**
     * 調整目前選擇中的條目
     */
    public void adjustMarker(boolean adjustPosition) {
        final int previous = mCurrentLineIndex;

        switch (mOrientation) {
            case VERTICAL: {
                int startY = (getHeight() >> 1) - getPaddingBottom();
                int scrollY = getScrollY();
                int progress = scrollY - startY;
                mCurrentLineIndex = -progress / space;

                if (mCurrentLineIndex > mLines) mCurrentLineIndex = mLines;
                else if (mCurrentLineIndex < 0) mCurrentLineIndex = 0;

                int expectY = space * -mCurrentLineIndex + startY;
                if (adjustPosition && scrollY != expectY) {
                    //scrollTo(0, expectY);
                    mOverScroller.startScroll(0, getScrollY(), 0, expectY - scrollY, 0);
                    ViewCompat.postInvalidateOnAnimation(this);
                }
            }
            break;
            case HORIZONTAL: {
                int startX = -((getWidth() >> 1) - getPaddingLeft());
                int scrollX = getScrollX();
                int progress = startX - scrollX;
                mCurrentLineIndex = -progress / space;
                if (mCurrentLineIndex > mLines) mCurrentLineIndex = mLines;
                else if (mCurrentLineIndex < 0) mCurrentLineIndex = 0;

                int expectX = space * mCurrentLineIndex + startX;

                if (adjustPosition && scrollX != expectX) {
                    //scrollTo(0, expectY);
                    mOverScroller.startScroll(getScrollX(), 0, expectX - scrollX, 0, 0);
                    ViewCompat.postInvalidateOnAnimation(this);
                }
            }
            break;
        }
        if (previous != mCurrentLineIndex) onValueChanged();
    }

    /**
     * 當值可能發生變化後執行
     */
    public void onValueChanged() {
        if (mCurrentLineIndex >= 0 && mCurrentLineIndex <= mLines) {
            int index = mCurrentLineIndex;
            int value = mStartLineValue + (index * mSetupValue);
            if (mOnItemChangedListener != null) mOnItemChangedListener.onItemChanged(index, value);
        }
    }

    @Override
    public void computeScroll() {
        if (mOverScroller.computeScrollOffset()) {
            mPreviousIsFling = true;
            switch (mOrientation) {
                case VERTICAL:
                    scrollTo(0, mOverScroller.getCurrY());
                    break;
                case HORIZONTAL:
                    scrollTo(mOverScroller.getCurrX(), 0);
                    break;
            }
            ViewCompat.postInvalidateOnAnimation(this);
        } else {
            if (mPreviousIsFling) {
                mPreviousIsFling = false;
                adjustMarker(true);
            }
        }
    }

    /**
     * 重置線組
     */
    private void resetLinesArr() {
        if (mLinesArr.length < (mLines + 1) * 4) {
            //須要從新建立數組
            mLinesArr = new float[(mLines + 1) * 4];
        } else {
            Arrays.fill(mLinesArr, 0);
        }
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        adjustMarker(false);
        canvas.drawColor(mBackgroundColor);
        switch (mOrientation) {
            case VERTICAL:
                drawVertical(canvas);
                break;
            case HORIZONTAL:
                drawHorizontal(canvas);
                break;
        }
    }

    /**
     * 繪製 方向爲垂直方向時的佈局
     *
     * @param canvas 畫布
     */
    protected void drawVertical(Canvas canvas) {
        //vertical mode
        // bottom start position
        int bottom = getHeight() - getPaddingBottom();
        int left = getPaddingLeft();

        float maxTextWidth = mTextPaint.measureText(String.valueOf((mLines+mStartLineValue) / mOutSideLine * mSetupValue));

        int shakeCenter = (getHeight() >> 1) + getScrollY();

        //繪製三角形
        //若是想使用圖片,能夠自行繪製圖片
//        mMarkerPath.reset();
//        mMarkerPath.moveTo(left + maxTextWidth + mLongLineLength + mMarkerSpace, shakeCenter);
//        mMarkerPath.lineTo(left + maxTextWidth + mLongLineLength + mMarkerSpace + mMarkerWidth, shakeCenter - mMarkerWidth);
//        mMarkerPath.lineTo(left + maxTextWidth + mLongLineLength + mMarkerSpace + mMarkerWidth, shakeCenter + mMarkerWidth);
//        mMarkerPath.lineTo(left + maxTextWidth + mLongLineLength + mMarkerSpace, shakeCenter);
//        canvas.drawPath(mMarkerPath, mMarkerPaint);

        resetLinesArr();

        for (int i = 0; i <= mLines; i++) {
            int value = mStartLineValue + (i * mSetupValue);
            float lineLength;
            switch (i % mOutSideLine) {
                case ZERO:
                    String text = String.valueOf(value);
                    float currentTextWidth = mTextPaint.measureText(text);
                    canvas.drawText(text, left + (maxTextWidth - currentTextWidth) / 2, bottom - i * space, mTextPaint);
                    lineLength = mLongLineLength;
                    break;
                default:
                    lineLength = mShortLineLength;
                    break;
            }
            mLinesArr[i * 4] = left + maxTextWidth;
            mLinesArr[i * 4 + 1] = bottom - i * space;
            mLinesArr[i * 4 + 2] = left + maxTextWidth + lineLength;
            mLinesArr[i * 4 + 3] = bottom - i * space;
        }

        //繪製線
        canvas.drawLines(mLinesArr, mPaint);
        //繪製高亮線
        canvas.drawLine(left + maxTextWidth,
                bottom - mCurrentLineIndex * space,
                left + maxTextWidth + (((mCurrentLineIndex) % mOutSideLine == 0) ? mLongLineLength : mShortLineLength),
                bottom - mCurrentLineIndex * space,
                mHighlightPaint);
    }

    /**
     * 繪製水平方向上的佈局
     *
     * @param canvas 畫布
     */
    protected void drawHorizontal(Canvas canvas) {

        //Horizontal mode
        // bottom position
        int bottom = getHeight() - getPaddingBottom();
        int left = getPaddingLeft();

        float maxTextWidth = mTextPaint.measureText(String.valueOf(mLines / mOutSideLine * mSetupValue));

        //中心
        int shakeCenter = (getWidth() >> 1) + getScrollX();

        //三角形頂點
        float vertexY = getHeight() - getPaddingBottom() - mTextPaint.getTextSize() - mLongLineLength - mMarkerSpace;

        //繪製三角形
        mMarkerPath.reset();
        mMarkerPath.moveTo(shakeCenter, vertexY);
        mMarkerPath.lineTo(shakeCenter - mMarkerWidth, vertexY - mMarkerWidth);
        mMarkerPath.lineTo(shakeCenter + mMarkerWidth, vertexY - mMarkerWidth);
        mMarkerPath.lineTo(shakeCenter, vertexY);
        canvas.drawPath(mMarkerPath, mMarkerPaint);
        //驗證線組
        resetLinesArr();

        //生成線組

        for (int i = 0; i <= mLines; i++) {
            int value = mStartLineValue + (i * mSetupValue);
            float lineLength;
            switch (i % mOutSideLine) {
                case ZERO:
                    String text = String.valueOf(value);
                    canvas.drawText(text, left + i * space, bottom, mTextPaint);
                    lineLength = mLongLineLength;
                    break;
                default:
                    lineLength = mShortLineLength;
                    break;
            }

            /*startX*/
            mLinesArr[i * 4] = left + i * space;
            /*startY*/
            mLinesArr[i * 4 + 1] = bottom - mTextPaint.getTextSize();
            /*stopX*/
            mLinesArr[i * 4 + 2] = left + i * space;
            /*stopY*/
            mLinesArr[i * 4 + 3] = bottom - (mTextPaint.getTextSize() + lineLength);
        }

        //繪製線組
        canvas.drawLines(mLinesArr, mPaint);

//        //繪製當前選中的線條
        canvas.drawLine(left + mCurrentLineIndex * space,
                (bottom - mTextPaint.getTextSize()),
                left + mCurrentLineIndex * space,
                (bottom - mTextPaint.getTextSize()) - (mCurrentLineIndex % mOutSideLine == 0 ? mLongLineLength : mShortLineLength),
                mHighlightPaint);
    }


    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        adjustMarker(true);
    }

    public int getLines() {
        return mLines;
    }

    public void setLines(int mLines) {
        this.mLines = mLines;
        requestLayout();
    }

    public int getOutSideLine() {
        return mOutSideLine;
    }

    public void setOutSideLine(int mOutSideLine) {
        this.mOutSideLine = mOutSideLine;
        invalidate();
    }

    public int getSetupValue() {
        return mSetupValue;
    }

    public void setSetupValue(int mSetupValue) {
        this.mSetupValue = mSetupValue;
        invalidate();
    }

    public int getCurrentLineIndex() {
        return mCurrentLineIndex;
    }

    public void setCurrentLineIndex(int currentLineIndex) {
        int distance = currentLineIndex * space;
        if (mOverScroller != null && !mOverScroller.isFinished()) mOverScroller.abortAnimation();
        switch (mOrientation) {
            case HORIZONTAL:
                int startX = (getWidth() >> 1) - getPaddingLeft();
                scrollTo(distance - startX, getScrollY());
                break;
            case VERTICAL:
                int startY = ((getHeight() >> 1) - getPaddingBottom());
                scrollTo(getScrollX(), -distance + startY);
                break;
        }
        adjustMarker(true);
        postInvalidate();
    }

    public int getSpace() {
        return space;
    }

    public void setSpace(int space) {
        this.space = space;
        requestLayout();
    }

    public float getShortLineLength() {
        return mShortLineLength;
    }

    public void setShortLineLength(float mShortLineLength) {
        this.mShortLineLength = mShortLineLength;
        invalidate();
    }

    public float getLongLineLength() {
        return mLongLineLength;
    }

    public void setLongLineLength(float mLongLineLength) {
        this.mLongLineLength = mLongLineLength;
        invalidate();
    }

    public int getHighLightColor() {
        return mHighLightColor;
    }

    public void setHighLightColor(int highLightColor) {
        this.mHighLightColor = highLightColor;
        mHighlightPaint.setColor(highLightColor);
        invalidate();
    }

    public int getTextColor() {
        return mTextColor;
    }

    public void setTextColor(int textColor) {
        this.mTextColor = textColor;
        mTextPaint.setColor(textColor);
        invalidate();
    }

    public float getTextSize() {
        return mTextSize;
    }

    public void setTextSize(float textSize) {
        this.mTextSize = textSize;
        mTextPaint.setTextSize(textSize);
        requestLayout();
    }

    public float getHighlightWidth() {
        return mHighlightWidth;
    }

    public void setHighlightWidth(float highlightWidth) {
        this.mHighlightWidth = highlightWidth;
        mHighlightPaint.setStrokeWidth(highlightWidth);
        requestLayout();
    }

    public float getLineWidth() {
        return mLineWidth;
    }

    public void setLineWidth(float lineWidth) {
        this.mLineWidth = lineWidth;
        mPaint.setStrokeWidth(lineWidth);
        requestLayout();
    }

    public int getLineColor() {
        return mLineColor;
    }

    public void setLineColor(int lineColor) {
        this.mLineColor = lineColor;
        mPaint.setColor(lineColor);
        invalidate();
    }


    public int getStartLineValue() {
        return mStartLineValue;
    }

    public void setStartLineValue(int startLineValue) {
        this.mStartLineValue = startLineValue;
        requestLayout();
    }

    public int getOrientation() {
        return mOrientation;
    }

    public void setOrientation(int orientation) {
        this.mOrientation = orientation;
        requestLayout();
    }

    public int getMarkerWidth() {
        return mMarkerWidth;
    }

    public void setMarkerWidth(int markerWidth) {
        this.mMarkerWidth = markerWidth;
        requestLayout();
    }

    public int getMarkerSpace() {
        return mMarkerSpace;
    }

    public void setMarkerSpace(int markerSpace) {
        this.mMarkerSpace = markerSpace;
        requestLayout();
    }

    public int getBackgroundColor() {
        return mBackgroundColor;
    }

    public void setBackgroundColor(int backgroundColor) {
        this.mBackgroundColor = backgroundColor;
        invalidate();
    }

    public int getMarkerColor() {
        return mMarkerColor;
    }

    public void setMarkerColor(int markerColor) {
        this.mMarkerColor = markerColor;
        mMarkerPaint.setColor(markerColor);
        invalidate();
    }

    public float getRatio() {
        return ratio;
    }

    /**
     * 設置阻尼係數
     *
     * @param ratio 須要設置的阻尼係數,默認的是 {@link #DEFAULT_RATIO}
     */
    public void setRatio(float ratio) {
        this.ratio = ratio;
    }

    /**
     * 設置item變化監聽器
     *
     * @param listener 須要設置item變化監聽器
     */
    public void setOnItemChangedListener(OnItemChangedListener listener) {
        this.mOnItemChangedListener = listener;
    }


    /**
     * 條目變化監聽器
     */
    public interface OnItemChangedListener {
        /**
         * 當條目發生變化後調用
         *
         * @param index 當前的選擇中的條目的下表
         * @param value 選擇中的條目的值
         */
        void onItemChanged(int index, int value);
    }

}

 

 

具體源碼:https://github.com/zhangchunbin/Demo_Customer_view/blob/master/app/src/main/java/com/bingo/customer/view/scrollrulerview/HeightView.javapost

相關文章
相關標籤/搜索