拒絕第三方--寫一個環形進度條

上一篇,介紹瞭如何做一個橫向的進度條,非常簡單。

今天,我們趁熱打鐵,做一個常見的環形進度條。諾,長下面這個樣子↓

一、分析

按照慣例,先分析元素。這裏,跟畫橫向進度條的不同是,橫向進度條是畫兩個圓角矩形,這裏,我們需要花兩個圓(進度條是根據實時進度值畫出的圓弧,最終補全爲360°的圓)。

 

1、背景環顏色

2、背景環&進度條相同的畫筆width

3、背景環設置爲空心

4、進度條顏色

5、文字顏色、字體大小

二、實現

因爲跟橫向進度條有許多相似的地方,不同之處,也就在onDraw的實現上,此處,就在前一篇文章的橫向進度條的基礎上進行完善。之後,使用這一個工具類,你只需稍作修改就可以實現橫向、環形進度條,靈活使用很Happy。

這裏,在attr中,多加入一個變量,cp_orientation,來區分進度條的形式,是橫向的還是環形的。

    <declare-styleable name="CustomProgressView">
        <!--百分比文字大小-->
        <attr name="cp_percent_textsize" format="dimension"/>
        <!--百分比文字顏色-->
        <attr name="cp_percent_textcolor" format="color|integer"/>
        <!--進度條背景顏色-->
        <attr name="cp_background_color" format="color|integer"/>
        <!--進度條背景是否空心-->
        <attr name="cp_background_is_stroke" format="boolean"/>
        <!--進度條顏色-->
        <attr name="cp_progress_color" format="color|integer"/>
        <!--進度條圓角值-->
        <attr name="cp_rect_round" format="dimension"/>
        <!--進度條形式-->
        <attr name="cp_orientation">
            <enum name="horizontal" value="0"/>
            <enum name="circle" value="1"/>
        </attr>

    </declare-styleable>

根據不同的取值,來畫不同的進度條

    @Override
    protected void onDraw(Canvas canvas) {
        mCenterX = getWidth() / 2;
        mCenterY = getHeight() / 2;

        if (cp_orientation == HORIZONTAL) {
            drawHorProgress(mPaint, canvas);
        } else if (cp_orientation == CIRCLE) {
            drawCircleProgress(mPaint, canvas);
        }

    }

    //畫環形進度條
    private void drawCircleProgress(Paint paint, Canvas canvas) {
        //畫背景環
        paint.setColor(cp_background_color);
        if (cp_background_is_stroke) {
            paint.setStyle(Paint.Style.STROKE);
            paint.setStrokeWidth(paint_width);
        } else {
            paint.setStyle(Paint.Style.FILL);
        }

        int radius = (int) (Math.min(getWidth() / 2, getHeight() / 2) - paint.getStrokeWidth() / 2);

        canvas.drawCircle(mCenterX, mCenterY, radius, paint);

        //畫進度環
        paint.setColor(cp_progress_color);
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeWidth(paint_width);

        RectF rectF = new RectF(mCenterX - radius, mCenterY - radius, mCenterX + radius, mCenterY + radius);

        canvas.drawArc(rectF, -90, 360 * progressCurrent / progressMax, false, paint);

        //畫文字
        paint.setColor(cp_percent_textcolor);
        paint.setTextSize(cp_percent_textsize);
        paint.setStyle(Paint.Style.FILL);
        String value_str = (int) (progressCurrent * 100 / progressMax) + "%";
        Rect rect = new Rect();
        paint.getTextBounds(value_str, 0, value_str.length(), rect);

        float textWidth = rect.width();
        float textHeight = rect.height();
        if (textWidth >= radius * 2) {
            textWidth = radius * 2;
        }
        Paint.FontMetrics metrics = paint.getFontMetrics();
        float baseline = (getMeasuredHeight() - metrics.bottom + metrics.top) / 2 - metrics.top;
        canvas.drawText(value_str, mCenterX - textWidth / 2, baseline, paint);


    }

這裏,在計算半徑時,選擇getWidth和getHeight的最小值,然後減去畫筆寬度的一半。這樣,使這個圓被包裹在view的佈局之中。圓的大小可以根據佈局寬高的變化進行動態調整。

進度環,畫的是圓弧;進度背景畫的是圓,兩者有區別,如果你不熟悉畫圓弧,可以去熟悉一下這方面的知識。

最後,注意一下,文字的大小不要超出圓的直徑。

三、佈局

    <net.feelingtech.example_work.custom.ownprogress.CustomProgressView
        android:id="@+id/cpv_circle"
        android:layout_width="match_parent"
        android:layout_height="100dp"
        android:layout_marginTop="20dp" />

四、跑起來

        mCpv_circle = view.findViewById(R.id.cpv_circle);
        mCpv_circle.setCp_orientation(1);
        mCpv_circle.setCp_background_is_stroke(true);
        mCpv_circle.setPaint_width(DensityUtil.dip2px(getContext(),10));
        mCpv_circle.setCp_background_color(Color.parseColor("#A2CD5A"));
        mCpv_circle.setProgressMax(100);
        mCpv_circle.setCp_progress_color(Color.RED);
        mCpv_circle.setCp_percent_textsize(DensityUtil.dip2px(getContext(), 16));
        mCpv_circle.setCp_percent_textcolor(Color.RED);



        view.findViewById(R.id.bt_start).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (progressCurrent != 0) {
                    progressCurrent = 0;
                    return;
                }
                mRunnable = new Runnable() {
                    @Override
                    public void run() {

                        progressCurrent += 1;
                        mCustomProgressView.setProgressCurrent(progressCurrent);
                        mCpv_circle.setProgressCurrent(progressCurrent);
                        mHandler.postDelayed(mRunnable, 5);

                    }
                };
                mHandler.postDelayed(mRunnable, 1);
            }
        });

五、完整代碼

public class CustomProgressView extends View {

    private int     cp_percent_textsize     = 18;//百分比字體大小
    private int     cp_percent_textcolor    = 0xff009ACD;
    private int     cp_background_color     = 0xff636363;
    private int     cp_progress_color       = 0xff00C5CD;
    private boolean cp_background_is_stroke = true;
    private int     cp_rect_round           = 5;
    private int     HORIZONTAL              = 0;
    private int     CIRCLE                  = 1;
    private int     cp_orientation          = HORIZONTAL;
    private Paint mPaint;
    private int   mCenterX;
    private int   mCenterY;

    private int progressCurrent = 0;
    private int progressMax     = 100;

    private int paint_width = 10;


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

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

    public CustomProgressView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        TypedArray typedArray = context.obtainStyledAttributes(R.styleable.CustomProgressView);
        cp_percent_textsize = (int) typedArray.getDimension(R.styleable.CustomProgressView_cp_percent_textsize, cp_percent_textsize);
        cp_percent_textcolor = typedArray.getColor(R.styleable.CustomProgressView_cp_percent_textcolor, cp_percent_textcolor);
        cp_background_color = typedArray.getColor(R.styleable.CustomProgressView_cp_background_color, cp_background_color);
        cp_progress_color = typedArray.getColor(R.styleable.CustomProgressView_cp_progress_color, cp_progress_color);
        cp_background_is_stroke = typedArray.getBoolean(R.styleable.CustomProgressView_cp_background_is_stroke, cp_background_is_stroke);
        cp_rect_round = (int) typedArray.getDimension(R.styleable.CustomProgressView_cp_rect_round, cp_rect_round);
        cp_orientation = typedArray.getInteger(R.styleable.CustomProgressView_cp_orientation, cp_orientation);
        typedArray.recycle();

        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);

    }

    @Override
    protected void onDraw(Canvas canvas) {
        mCenterX = getWidth() / 2;
        mCenterY = getHeight() / 2;

        if (cp_orientation == HORIZONTAL) {
            drawHorProgress(mPaint, canvas);
        } else if (cp_orientation == CIRCLE) {
            drawCircleProgress(mPaint, canvas);
        }

    }

    //畫環形進度條
    private void drawCircleProgress(Paint paint, Canvas canvas) {
        //畫背景環
        paint.setColor(cp_background_color);
        if (cp_background_is_stroke) {
            paint.setStyle(Paint.Style.STROKE);
            paint.setStrokeWidth(paint_width);
        } else {
            paint.setStyle(Paint.Style.FILL);
        }

        int radius = (int) (Math.min(getWidth() / 2, getHeight() / 2) - paint.getStrokeWidth() / 2);

        canvas.drawCircle(mCenterX, mCenterY, radius, paint);

        //畫進度環
        paint.setColor(cp_progress_color);
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeWidth(paint_width);

        RectF rectF = new RectF(mCenterX - radius, mCenterY - radius, mCenterX + radius, mCenterY + radius);

        canvas.drawArc(rectF, -90, 360 * progressCurrent / progressMax, false, paint);

        //畫文字
        paint.setColor(cp_percent_textcolor);
        paint.setTextSize(cp_percent_textsize);
        paint.setStyle(Paint.Style.FILL);
        String value_str = (int) (progressCurrent * 100 / progressMax) + "%";
        Rect rect = new Rect();
        paint.getTextBounds(value_str, 0, value_str.length(), rect);

        float textWidth = rect.width();
        float textHeight = rect.height();
        if (textWidth >= radius * 2) {
            textWidth = radius * 2;
        }
        Paint.FontMetrics metrics = paint.getFontMetrics();
        float baseline = (getMeasuredHeight() - metrics.bottom + metrics.top) / 2 - metrics.top;
        canvas.drawText(value_str, mCenterX - textWidth / 2, baseline, paint);


    }

    //畫線性進度條
    private void drawHorProgress(Paint paint, Canvas canvas) {
        //畫背景
        paint.setColor(cp_background_color);
        if (cp_background_is_stroke) {
            paint.setStyle(Paint.Style.STROKE);
            paint.setStrokeWidth(1);
        } else {
            paint.setStyle(Paint.Style.FILL);
        }

        canvas.drawRoundRect(new RectF(mCenterX - getWidth() / 2, mCenterY - getHeight() / 2,
                mCenterX + getWidth() / 2, mCenterY + getHeight() / 2), cp_rect_round, cp_rect_round, paint);

        //畫進度條
        paint.setColor(cp_progress_color);
        paint.setStyle(Paint.Style.FILL);

        canvas.drawRoundRect(new RectF(mCenterX - getWidth() / 2, mCenterY - getHeight() / 2,
                (int) (progressCurrent * getWidth() / progressMax), mCenterY + getHeight() / 2), cp_rect_round, cp_rect_round, paint);

        //畫文字
        paint.setColor(cp_percent_textcolor);
        paint.setTextSize(cp_percent_textsize);
        paint.setStyle(Paint.Style.FILL);
        String value_str = (int) (progressCurrent * 100 / progressMax) + "%";
        Rect rect = new Rect();
        paint.getTextBounds(value_str, 0, value_str.length(), rect);

        float textWidth = rect.width();
        float textHeight = rect.height();
        if (textWidth >= getWidth()) {
            textWidth = getWidth();
        }
        Paint.FontMetrics metrics = paint.getFontMetrics();
        float baseline = (getMeasuredHeight() - metrics.bottom + metrics.top) / 2 - metrics.top;
        canvas.drawText(value_str, mCenterX - textWidth / 2, baseline, paint);

    }

    public int getCp_percent_textsize() {
        return cp_percent_textsize;
    }

    public void setCp_percent_textsize(int cp_percent_textsize) {
        this.cp_percent_textsize = cp_percent_textsize;
    }

    public int getCp_percent_textcolor() {
        return cp_percent_textcolor;
    }

    public void setCp_percent_textcolor(int cp_percent_textcolor) {
        this.cp_percent_textcolor = cp_percent_textcolor;
    }

    public int getCp_background_color() {
        return cp_background_color;
    }

    public void setCp_background_color(int cp_background_color) {
        this.cp_background_color = cp_background_color;
    }

    public int getCp_progress_color() {
        return cp_progress_color;
    }

    public void setCp_progress_color(int cp_progress_color) {
        this.cp_progress_color = cp_progress_color;
    }

    public boolean isCp_background_is_stroke() {
        return cp_background_is_stroke;
    }

    public void setCp_background_is_stroke(boolean cp_background_is_stroke) {
        this.cp_background_is_stroke = cp_background_is_stroke;
    }

    public int getCp_rect_round() {
        return cp_rect_round;
    }

    public void setCp_rect_round(int cp_rect_round) {
        this.cp_rect_round = cp_rect_round;
    }

    public int getProgressCurrent() {
        return progressCurrent;
    }

    public void setProgressCurrent(int progressCurrent) {
        if (progressCurrent > progressMax) {
            this.progressCurrent = progressMax;
        } else {
            this.progressCurrent = progressCurrent;
        }
        postInvalidate();
    }

    public int getProgressMax() {
        return progressMax;
    }

    public void setProgressMax(int progressMax) {
        this.progressMax = progressMax;
    }

    public int getCp_orientation() {
        return cp_orientation;
    }

    public void setCp_orientation(int cp_orientation) {
        this.cp_orientation = cp_orientation;
    }

    public int getPaint_width() {
        return paint_width;
    }

    public void setPaint_width(int paint_width) {
        this.paint_width = paint_width;
    }
}

 

長按關注,共同進步

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章