【Android自定义控件】打造炫酷进度条

1.使用TypedValue将dp或者sp转换为px

TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpVal,getResources().getDisplayMetrics());
TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, spVal,getResources().getDisplayMetrics());

2.Paint.ascent():baseline之上至字符最高处的距离;
Paint.descent():baseline之下至字符最低处的距离;
Paint.measureText():获取字符串的宽度;
Paint.getTextBounds():获取字符串的边界宽度;
3.绘制文字的基准线

int y = (int) (-(mPaint.ascent() + mPaint.descent()) / 2);

4.resolveSize

public static int resolveSizeAndState(int size, int measureSpec, int childMeasuredState) {
        final int specMode = MeasureSpec.getMode(measureSpec);
        final int specSize = MeasureSpec.getSize(measureSpec);
        final int result;
        switch (specMode) {
            case MeasureSpec.AT_MOST:
                if (specSize < size) {
                    result = specSize | MEASURED_STATE_TOO_SMALL;
                } else {
                    result = size;
                }
                break;
            case MeasureSpec.EXACTLY:
                result = specSize;
                break;
            case MeasureSpec.UNSPECIFIED:
            default:
                result = size;
        }
        return result | (childMeasuredState & MEASURED_STATE_MASK);
    }

5.水平进度条完整代码

public class HorizontalProgressBar extends ProgressBar {

    private static final int DEFAULT_TEXT_SIZE = 10;
    private static final int DEFAULT_TEXT_COLOR = 0xFFFF0000;
    private static final int DEFAULT_TEXT_OFFSET = 10;
    private static final int DEFAULT_REACH_COLOR = 0xFFFF0000;
    private static final int DEFAULT_REACH_HEIGHT = 2;
    private static final int DEFAULT_UNREACH_COLOR = 0x44FF0000;
    private static final int DEFAULT_UNREACH_HEIGHT = 2;

    protected int mTextSize = sp2px(DEFAULT_TEXT_SIZE);
    protected int mTextColor = DEFAULT_TEXT_COLOR;
    protected int mTextOffset = dp2px(DEFAULT_TEXT_OFFSET);
    protected int mReachColor = DEFAULT_REACH_COLOR;
    protected int mReachHeight = dp2px(DEFAULT_REACH_HEIGHT);
    protected int mUnreachColor = DEFAULT_UNREACH_COLOR;
    protected int mUnreachHeight = dp2px(DEFAULT_UNREACH_HEIGHT);

    protected Paint mPaint = new Paint();
    protected int mRealWidth;

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

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

    public HorizontalProgressBar(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        TypedArray typedArray = getContext().obtainStyledAttributes(attrs, R.styleable.HorizontalProgressBar);
        mTextColor = typedArray.getColor(R.styleable.HorizontalProgressBar_progress_text_color, mTextColor);
        mTextSize = (int) typedArray.getDimension(R.styleable.HorizontalProgressBar_progress_text_size, mTextSize);
        mTextOffset = (int) typedArray.getDimension(R.styleable.HorizontalProgressBar_progress_text_offset, mTextOffset);
        mReachColor = typedArray.getColor(R.styleable.HorizontalProgressBar_progress_reach_color, mReachColor);
        mReachHeight = (int) typedArray.getDimension(R.styleable.HorizontalProgressBar_progress_reach_height, mReachHeight);
        mUnreachColor = typedArray.getColor(R.styleable.HorizontalProgressBar_progress_unreach_color, mUnreachColor);
        mUnreachHeight = (int) typedArray.getDimension(R.styleable.HorizontalProgressBar_progress_unreach_height, mUnreachHeight);
        typedArray.recycle();
        mPaint.setTextSize(mTextSize);
    }

    @Override
    protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightSize = measureHeightSize(heightMeasureSpec);
        setMeasuredDimension(widthSize, heightSize);
        mRealWidth = getMeasuredWidth() - getPaddingLeft() - getPaddingRight();
    }

    private int measureHeightSize(int heightMeasureSpec) {
        int result = 0;
        int size = MeasureSpec.getSize(heightMeasureSpec);
        int mode = MeasureSpec.getMode(heightMeasureSpec);
        if (mode == MeasureSpec.EXACTLY) {
            result = size;
        } else {
            int textHeight = (int) (mPaint.ascent() - mPaint.descent());
            result = getPaddingTop() + getPaddingBottom() +
                    Math.max(Math.max(mReachHeight, mUnreachHeight), Math.abs(textHeight));
            if (mode == MeasureSpec.AT_MOST) {
                result = Math.min(result, size);
            }

        }
        return result;
    }

    @Override
    protected synchronized void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //文字长度
        String text = getProgress() + "%";
        int textWidth = (int) mPaint.measureText(text);
        canvas.save();
        //画布坐标平移到paddingLeft,1/2高度处
        canvas.translate(getPaddingLeft(), getHeight() / 2);
        //进度比例
        float radio = getProgress() * 1.0f / getMax();
        //第一段长度
        float progressX = (mRealWidth - textWidth - mTextOffset) * radio;
//        float endX = progressX - mTextOffset/2;

        //是否需要绘制第二段
        boolean noNeedUnreach = false;
        if (progressX + textWidth + mTextOffset / 2 > mRealWidth) {
            progressX = mRealWidth - textWidth - mTextOffset / 2;
            noNeedUnreach = true;
        }

        //绘制第一段进度条
        mPaint.setColor(mReachColor);
        mPaint.setStrokeWidth(mReachHeight);
        canvas.drawLine(0, 0, progressX, 0, mPaint);
        //绘制文字
        mPaint.setColor(mTextColor);
        int y = (int) (-(mPaint.ascent() + mPaint.descent()) / 2);
        canvas.drawText(text, progressX + mTextOffset / 2, y, mPaint);
        //绘制第二段
        if (!noNeedUnreach) {
            mPaint.setColor(mUnreachColor);
            mPaint.setStrokeWidth(mUnreachHeight);
            canvas.drawLine(progressX + textWidth + mTextOffset, 0, mRealWidth, 0, mPaint);
        }

        canvas.restore();
    }

    protected int dp2px(int dpVal) {
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpVal,
                getResources().getDisplayMetrics());
    }

    protected int sp2px(int spVal) {
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, spVal,
                getResources().getDisplayMetrics());
    }

}

4.圆形进度条完整代码

public class RoundProgressBar extends HorizontalProgressBar {

    private int mRadius = dp2px(30);

    private int mMaxPaintWidth;


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

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

    public RoundProgressBar(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        TypedArray typedArray = getContext().obtainStyledAttributes(attrs, R.styleable.RoundProgressBar);
        mRadius = (int) typedArray.getDimension(R.styleable.RoundProgressBar_progress_radius, mRadius);
        typedArray.recycle();

        mReachHeight = (int) (mReachHeight * 2.5f);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setAntiAlias(true);
        mPaint.setDither(true);

    }

    @Override
    protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        mMaxPaintWidth = Math.max(mReachHeight, mUnreachHeight);
        int expect = mRadius * 2 + mMaxPaintWidth + getPaddingLeft() + getPaddingRight();
        int widthSize = resolveSize(expect, widthMeasureSpec);
        int heightSize = resolveSize(expect, heightMeasureSpec);
        setMeasuredDimension(widthSize, heightSize);

        int realWidth = Math.min(widthSize, heightSize);
        mRadius = (realWidth - getPaddingLeft() - getPaddingRight() - mMaxPaintWidth) / 2;

    }

    @Override
    protected synchronized void onDraw(Canvas canvas) {
        String text = getProgress() + "%";
        int textWidth = (int) mPaint.measureText(text);
        int textHeight = (int) (mPaint.ascent() - mPaint.descent());
        canvas.save();
        //绘制圆
        canvas.translate(getPaddingLeft() + mMaxPaintWidth / 2, getPaddingTop() + mMaxPaintWidth / 2);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setColor(mUnreachColor);
        mPaint.setStrokeWidth(mUnreachHeight);
        canvas.drawCircle(mRadius, mRadius, mRadius, mPaint);
        //绘制弧
        mPaint.setColor(mReachColor);
        mPaint.setStrokeWidth(mReachHeight);
        float sweep = getProgress() * 1.0f / getMax() * 360;
        canvas.drawArc(new RectF(0, 0, mRadius *2 , mRadius *2), 0, sweep, false, mPaint);
        //绘制文字
        mPaint.setStyle(Paint.Style.FILL);
        mPaint.setColor(mTextColor);
        mPaint.setStrokeWidth(mTextSize);
        canvas.drawText(text, mRadius - textWidth / 2, mRadius - textHeight / 2, mPaint);

        canvas.restore();
    }
}

你可能感兴趣的:(Android实战)