自定義進度條(ProgressBar)

imooc視頻地址

同樣是自定義view的練習。

圖片錄製有問題,將就看吧。
效果圖:
這裏寫圖片描述

思路:
1. 繼承ProgressBar
2. 實現其構造器
3. 初始化畫筆 、提取xml屬性
4. 測量
5. 繪圖

傳統進度條

繼承ProgressBar

public class MyProgressBar1_Horizontal extends ProgressBar{}

實現其構造器

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

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

public MyProgressBar1_Horizontal(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    init();
    parseStyle(context, attrs);

初始化畫筆 、提取xml屬性

//提取xml屬性
private void parseStyle(Context context, AttributeSet attr) {
    TypedArray typedArray = context.obtainStyledAttributes(attr, R.styleable.MyProgressBar1_Horizontal);

    color_text = typedArray.getColor(R.styleable.MyProgressBar1_Horizontal_colortext, COLOR_TEXT);
    color_fore = typedArray.getColor(R.styleable.MyProgressBar1_Horizontal_colorfore, COLOR_FORE);
    color_background = typedArray.getColor(R.styleable.MyProgressBar1_Horizontal_colorbackground, COLOR_BACKGROUND);

    height_text = (int) typedArray.getDimension(R.styleable.MyProgressBar1_Horizontal_heighttext, HEIGHT_TEXT);
    height_fore = (int) typedArray.getDimension(R.styleable.MyProgressBar1_Horizontal_heightfore, HEIGHT_FORE);
    height_background = (int) typedArray.getDimension(R.styleable.MyProgressBar1_Horizontal_heightbacground, HEIGHT_BACKGROUND);

    gap = (int) typedArray.getDimension(R.styleable.MyProgressBar1_Horizontal_gap, GAP);

    typedArray.recycle();
}
//初始化畫筆
protected void init() {
    paint = new Paint();
    paint.setStyle(Paint.Style.STROKE);
    paint.setAntiAlias(true);
    paint.setDither(true);
    paint.setStrokeCap(Paint.Cap.ROUND);
}

測量

@Override
protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    int width = MeasureSpec.getSize(widthMeasureSpec);
    int height = measureHeight(heightMeasureSpec);
    drawWiath = width - getPaddingLeft() - getPaddingRight();
    drawHeight = height;
    setMeasuredDimension(width, height);
}

private int measureHeight(int heightMeasureSpec) {

    if (MeasureSpec.getMode(heightMeasureSpec) != MeasureSpec.EXACTLY) {
        return Math.max(Math.max(height_background, height_fore), height_text);
    }
    return MeasureSpec.getSize(heightMeasureSpec);
}

繪圖

@Override
protected synchronized void onDraw(Canvas canvas) {
    canvas.save();
//        canvas.translate();//這裏沒有移動座標
    float percentage = getProgress() * 1.0f / getMax();
    String text = getProgress() + "%";
    float measureText = paint.measureText(text);

    if (measureText + percentage * drawWiath + gap / 2 <= drawWiath) {

        paint.setStrokeCap(Paint.Cap.ROUND);
        paint.setStrokeWidth(height_fore);
        paint.setColor(color_fore);
        canvas.drawLine(0, drawHeight / 2, percentage * drawWiath, drawHeight / 2, paint);


        paint.setStyle(Paint.Style.FILL);
        paint.setTextSize(height_text);
        paint.setStrokeWidth(height_text);
        paint.setColor(color_text);
        canvas.drawText(text, percentage * drawWiath + gap / 2, drawHeight / 2 - (paint.descent() + paint.ascent() / 2), paint);
        measureText = paint.measureText(text);

        paint.setStrokeCap(Paint.Cap.ROUND);
        paint.setStrokeWidth(height_background);
        paint.setColor(color_background);
        canvas.drawLine(percentage * drawWiath + gap + measureText, drawHeight / 2, drawWiath, drawHeight / 2, paint);
    } else {
        paint.setStrokeCap(Paint.Cap.ROUND);
        paint.setStrokeWidth(height_fore);
        paint.setColor(color_fore);
        canvas.drawLine(0, drawHeight / 2, drawWiath - measureText - gap/2, drawHeight / 2, paint);

        paint.setStyle(Paint.Style.FILL);
        paint.setTextSize(height_text);
        paint.setStrokeWidth(height_text);
        paint.setColor(color_text);
        canvas.drawText(text, drawWiath - measureText, (drawHeight - paint.descent() - paint.ascent()) / 2, paint);

    }


    canvas.restore();
}

其他的大致都是這個思路。
比如圓形的:同樣是重複上面的步驟,只不過測量和繪圖時會有寫不同

測量:以寬高中最小的一方爲圓的半徑
繪製:

    @Override
    protected synchronized void onDraw(Canvas canvas) {

        paint.setDither(true);
        paint.setAntiAlias(true);

        String text = getProgress() + "%";
        float textWidth;
        float textHeight = paint.descent() + paint.ascent();
        float sweepAngle = getProgress() * 1.0f / getMax() * 360;//角度
        RectF rectF = new RectF(0, 0, drawRadius * 2, drawRadius * 2);

        canvas.save();
        canvas.translate(getPaddingLeft() + maxPaintWidth / 2, getPaddingTop() + maxPaintWidth / 2);
        //背景
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeWidth(height_background);
        paint.setColor(color_background);
        canvas.drawCircle(drawRadius, drawRadius, drawRadius, paint);
        //前景
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeWidth(height_fore);
        paint.setColor(color_fore);
        canvas.drawArc(rectF, 0, sweepAngle, false, paint);
        //文字
        paint.setStyle(Paint.Style.FILL);
        paint.setColor(color_text);
        paint.setTextSize(height_text);
        paint.setStrokeWidth(height_text);
        textWidth = paint.measureText(text);
        canvas.drawText(text, drawRadius - textWidth / 2, drawRadius - textHeight / 2, paint);
        canvas.restore();
    }

在這裏要注意一點,在繪製文字時候,應該將畫筆設置爲paint.setStyle(Paint.Style.FILL);
如果畫筆仍然爲paint.setStyle(Paint.Style.STROKE);則會出現繪製失敗(繪製亂七八糟的)。

clip類型進度條(我也不知道叫啥)

效果就是效果圖下面的杯子。
顯示
1. 在佈局文件中寫出(不要在意我起什麼名字了)

<sunshine.myapplication.MyProgressBar_2 
    android:layout_width="wrap_content"
    android:layout_marginTop="300dp"
    android:layout_height="wrap_content"
    sunshine:max="100"
    sunshine:progress="80" />

2. 在drawable中創建一個 clip 便籤的xml文件

clipOrientation和gravity 可以控制顯示的方向位置等

 loading_progress是杯子的圖片
<?xml version="1.0" encoding="utf-8"?>
 <clip xmlns:android="http://schemas.android.com/apk/res/android"
    android:clipOrientation="vertical"
    android:drawable="@drawable/loading_progress"
    android:gravity="bottom" >
</clip>

3. 創建一個ImageView

這個ImageView其實就是顯示出來的控件,只不過我們在這個View上進行了一些小的‘內幕’操作

<?xml version="1.0" encoding="utf-8"?>
<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/myprogressbar_2"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center"
    android:paddingLeft="3dp"
    android:paddingTop="3dp"
    android:scaleType="centerInside"
    android:src="@drawable/myprogressbar_2" />

實現

對我們的ImageView進行“內幕”操作

public class MyProgressBar_2 extends FrameLayout {
    private final int DEF_MAX = 100;
    private final int DEF_PROGRESS = 0;
    private int pro = 0;
    private int max, progress;
    private ClipDrawable drawable;


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

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

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

    private void init(Context context, AttributeSet attrs) {

        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.MyProgressBar_2);
        max = typedArray.getInteger(R.styleable.MyProgressBar_2_max, DEF_MAX);
        progress = typedArray.getInteger(R.styleable.MyProgressBar_2_progress, DEF_PROGRESS);
        typedArray.recycle();
//看這裏
        View view = LayoutInflater.from(context).inflate(R.layout.myprogressbar_2, null);
        addView(view);

        ImageView imageView = (ImageView) findViewById(R.id.myprogressbar_2);
        drawable = (ClipDrawable) imageView.getDrawable();
        setProgress(progress);
    }


    public void setProgress(int progress) {
        pro = progress;
        if (pro > max)
            pro = max;
        drawable.setLevel(pro * (10000/ max ));
    }

    public int getProgress() {
        return pro;
    }

擴展

我們有時候可能會看見儀表盤這樣的進度條

其實原理還是一樣的
第一個:繪製的起點和中點發送了改變
第二個:其實是以圓直徑爲總長度,根據進度來繪製相應角度的扇形,然後將畫筆設置爲FILL就可以了(當時不知道設置爲fill就可以填充,走了點彎路)
至於那些有顏色漸變的,也就是將畫筆設置一下就可以了,網上有很多資料的。

差不多就到這裏了,學會舉一反三就好了,

分享一個專門做繪圖的第三方庫:XCL:http://www.oschina.net/p/xcl-charts
在鴻洋大神的微博上看見他分享了一個繪圖的,也拿來分享下:SmallChart https://github.com/Idtk/SmallChart

本週任務原應本月15號完成,實際爲12號完成。
任務完成~

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