Android 自定義View、ViewGroup 實戰訓練之CircleProgress

項目中很多時候時候會用到圓形的進度條,Android系統自帶的不太好看,通常我們都會去自定義它,今天我們來介紹一下自定義控件以及自定義屬性的使用。

先來看一下自定義CircleProgress的代碼,如果你看着太喫力,請先閱讀一下Android 自定義View、ViewGroup(一)之工作原理

public class CircleProgress extends View {

    public static final int STROKE = 0;
    public static final int FILL = 1;

    private Paint paint;

    private int circleColor;
    private int progressColor;
    private int textColor;
    private float textSize;
    private float circleWidth;
    private int circleMax;
    private boolean textIsDisplay;
    private int style;

    /**
     * 當前進度
     */
    private int progress;

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

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

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

        paint = new Paint();
        TypedArray mTypedArray = context.obtainStyledAttributes(attrs, R.styleable.CircleProgressBar);
        //獲取自定義屬性和默認值
        circleColor = mTypedArray.getColor(R.styleable.CircleProgressBar_circle_color, Color.RED);
        progressColor = mTypedArray.getColor(R.styleable.CircleProgressBar_circle_progress_color, Color.GREEN);
        textColor = mTypedArray.getColor(R.styleable.CircleProgressBar_text_color, Color.GREEN);
        textSize = mTypedArray.getDimension(R.styleable.CircleProgressBar_text_size, 15);
        circleWidth = mTypedArray.getDimension(R.styleable.CircleProgressBar_circle_width, 5);
        circleMax = mTypedArray.getInteger(R.styleable.CircleProgressBar_circle_max, 100);
        textIsDisplay = mTypedArray.getBoolean(R.styleable.CircleProgressBar_is_text_display, true);
        style = mTypedArray.getInt(R.styleable.CircleProgressBar_style, 0);

        mTypedArray.recycle();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        //1.畫出最外層的大圓環
        int center = getWidth()/2;
        int radius = (int) (center-circleWidth/2);
        paint.setColor(circleColor); //設置圓環的顏色
        paint.setStyle(Paint.Style.STROKE); //設置空心
        paint.setStrokeWidth(circleWidth); //設置圓環的寬度
        paint.setAntiAlias(true); //消除鋸齒
        canvas.drawCircle(center, center, radius, paint);

        //2.畫百分比
        paint.setStrokeWidth(0);
        paint.setColor(textColor);
        paint.setTextSize(textSize);
        paint.setTypeface(Typeface.DEFAULT_BOLD);
        int percent = (int) (((float) progress / (float) circleMax) * 100);
        float textWidth = paint.measureText(percent + "%");
        if (isTextIsDisplay() && percent != 0 && style == STROKE) {
            canvas.drawText(percent + "%", center - textWidth / 2, center + textSize / 2, paint);
        }

        //3.畫進度
        paint.setStrokeWidth(circleWidth);
        paint.setColor(progressColor);
        //用於定義的圓弧的形狀和大小的界限
        RectF oval = new RectF(center - radius, center - radius, center + radius, center + radius);

        switch (style) {
            case STROKE: {
                paint.setStyle(Paint.Style.STROKE);
                canvas.drawArc(oval, 0, 360 * progress / circleMax, false, paint);
                break;
            }
            case FILL: {
                paint.setStyle(Paint.Style.FILL_AND_STROKE);
                if (progress != 0)
                    canvas.drawArc(oval, 0, 360 * progress / circleMax, true, paint);
                break;
            }
        }
    }



    /**
     * 設置進度
     * @param progress
     */
    public synchronized void setProgress(int progress){
        if(progress < 0){
            throw new IllegalArgumentException("progress not less than 0");
        }
        if(progress > circleMax){
            progress = circleMax;
        }
        if(progress <= circleMax){
            this.progress = progress;
            postInvalidate();
        }
    }

    /**
     * 獲取進度
     * @return
     */
    public synchronized int getProgress(){
        return progress;
    }

    public synchronized int getCircleMax() {
        return circleMax;
    }

    public synchronized void setCircleMax(int circleMax) {
        if (circleMax < 0) {
            throw new IllegalArgumentException("max not less than 0");
        }
        this.circleMax = circleMax;
    }



    public int getCircleColor() {
        return circleColor;
    }

    public void setCircleColor(int circleColor) {
        this.circleColor = circleColor;
    }

    public int getProgressColor() {
        return progressColor;
    }

    public void setProgressColor(int progressColor) {
        this.progressColor = progressColor;
    }

    public int getTextColor() {
        return textColor;
    }

    public void setTextColor(int textColor) {
        this.textColor = textColor;
    }

    public float getTextSize() {
        return textSize;
    }

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

    public float getCircleWidth() {
        return circleWidth;
    }

    public void setCircleWidth(float circleWidth) {
        this.circleWidth = circleWidth;
    }

    public boolean isTextIsDisplay() {
        return textIsDisplay;
    }

    public void setTextIsDisplay(boolean textIsDisplay) {
        this.textIsDisplay = textIsDisplay;
    }

    public int getStyle() {
        return style;
    }

    public void setStyle(int style) {
        this.style = style;
    }
}
步驟如下:

1. 定義類繼承View重寫構造方法並初始化畫筆Paint

2. 根據Context的obtainStyledAttributes方法獲取屬性集,並獲取自定義屬性和默認值

3. 對外暴露get、set方法,讓外部可以設置和獲取指定值

4.重寫onDraw方法畫出大圓環、百分比和進度

如果想了解更多自定義進度條,請點擊

下載Demo請猛戳  AndroidStudio版

下載Demo請猛戳 Eclipse版

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