自定义进度条(ProgressBar)

版权声明:如需转载请在明显位置保留作者信息及原文链接 https://blog.csdn.net/qq_24889075/article/details/51854808

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号完成。
任务完成~

猜你喜欢

转载自blog.csdn.net/qq_24889075/article/details/51854808