博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android Paint应用之自定义View实现进度条控件
阅读量:6937 次
发布时间:2019-06-27

本文共 10034 字,大约阅读时间需要 33 分钟。

在上一篇文章学习了Paint的基本用法,但是具体的应用我们还没有实践过。从标题中可知,本文是带领读者使用Paint,自定义一个进度条控件。

上图就是本文要实现的效果图。既然是自定义控件,本文的该控件是直接继承View,然后重写View的onMeasure和onDraw方法来实现。其中onMeasure主要作用是测量控件的宽/高。而onDraw则是将界面绘制到屏幕上。

从效果的效果上看,我们需要自定义一些属性,如:进度度条的颜色、圆边框的颜色、圆边框的宽度和文本的大小等等。

具体的自定义属性请看下面attrs.xml的代码:

复制代码

接下来看本文的最重要部分,也就是自定义View

public class CustomProgressBar extends View {    private int max = 100;//总进度    private int roundColor = Color.RED;//进度圆弧的颜色    private float roundWidth = 10;//圆边框宽度    private int roundProgressColor = Color.BLUE;//默认的大圆环边框颜色    private float textSize = 55;//文本大小    private int textColor = Color.GREEN;//文本默认颜色    private boolean textShow = true;//是否展示文本    public static final int STROKE = 0;//描边    public static final int FILL = 1;//填充    private int style = STROKE;//默认描边    private int progress;//进度    private Paint mPaint;    private int mWidth = 200;//默认控件宽度,wrap_content时候使用    private int mHeight = 200;//默认控件高度,wrap_content时候使用    public CustomProgressBar(Context context) {        this(context, null);    }    public CustomProgressBar(Context context, @Nullable AttributeSet attrs) {        super(context, attrs);        init(context, attrs);    }    private void init(Context context, AttributeSet attrs) {        mPaint = new Paint();        if (attrs != null) {            TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CustomProgressBar);            max = typedArray.getInteger(R.styleable.CustomProgressBar_max, 100);            roundColor = typedArray.getColor(R.styleable.CustomProgressBar_roundColor, Color.BLUE);            roundProgressColor = typedArray.getColor(R.styleable.CustomProgressBar_roundProgressColor, Color.BLUE);            textColor = typedArray.getColor(R.styleable.CustomProgressBar_textColor, Color.GREEN);            textSize = typedArray.getDimension(R.styleable.CustomProgressBar_textSize, 55);            roundWidth = typedArray.getDimension(R.styleable.CustomProgressBar_roundWidth, 10);            textShow = typedArray.getBoolean(R.styleable.CustomProgressBar_textShow, true);            style = typedArray.getInt(R.styleable.CustomProgressBar_style, 0);            typedArray.recycle();        }    }    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        super.onMeasure(widthMeasureSpec, heightMeasureSpec);        int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);        int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);        int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);        int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);        if (widthSpecMode == MeasureSpec.AT_MOST && heightSpecMode == MeasureSpec.AT_MOST){            setMeasuredDimension(mWidth,mHeight);        }else if (widthSpecMode == MeasureSpec.AT_MOST){            setMeasuredDimension(mWidth,heightSpecSize);        }else if (heightSpecMode == MeasureSpec.AT_MOST){            setMeasuredDimension(widthSpecSize,mHeight);        }    }    @Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        final int paddingLeft = getPaddingLeft();        final int paddingRight = getPaddingRight();        final int paddingTop = getPaddingTop();        final int paddingBottom = getPaddingBottom();        int width = getWidth() - paddingLeft - paddingRight;        int height = getHeight() - paddingBottom - paddingTop;        //画默认的大圆环        float radius = (float)Math.min(width,height)/2.0f;//中心坐标点        mPaint.setColor(roundColor);        mPaint.setStyle(Paint.Style.STROKE);//描边        mPaint.setStrokeWidth(roundWidth);//圆环边的宽度//        if (style == STROKE){//            mPaint.setStrokeWidth(roundWidth);//圆环边的宽度//        }        mPaint.setAntiAlias(true);        //(float cx, float cy, float radius, @NonNull Paint paint)        canvas.drawCircle(paddingLeft+width/2,paddingTop+height/2,radius,mPaint);        //画进度百分比        mPaint.setColor(textColor);        mPaint.setStrokeWidth(0);//圆环的宽度        mPaint.setTextSize(textSize);        mPaint.setTypeface(Typeface.DEFAULT_BOLD);        int percent = (int)(progress/(float)max * 100);        if(textShow && percent!=0 && style == STROKE){            //(@NonNull String text, float x, float y, @NonNull Paint paint)            canvas.drawText(percent+"%", (getWidth()-mPaint.measureText(percent+"%"))/2f,                    //y公式: float baselineY = centerY + (fontMetrics.bottom-fontMetrics.top)/2 - fontMetrics.bottom                    getWidth()/2f-(mPaint.descent()+mPaint.ascent())/2f,                    mPaint);        }        //画圆弧        //矩形区域,定义圆弧的形状大小        //(float left, float top, float right, float bottom)        RectF oval = new RectF(paddingLeft, paddingTop, width+paddingLeft, height+paddingTop);        mPaint.setColor(roundProgressColor);        mPaint.setStrokeWidth(roundWidth);//圆环边的宽度        switch (style){            case STROKE:                mPaint.setStyle(Paint.Style.STROKE);                //(@NonNull RectF oval, float startAngle, float sweepAngle, boolean useCenter,@NonNull Paint paint)                //useCenter:设置圆弧在绘画的时候,是否经过圆形                canvas.drawArc(oval , 0, 360*progress/max, false, mPaint);                break;            case FILL:                mPaint.setStyle(Paint.Style.FILL_AND_STROKE);                if(progress!=0)                    canvas.drawArc(oval , 0, 360*progress/max, true, mPaint);                break;            default:                break;        }    }    public void setProgressWidth(int width) {        mWidth = width;    }    public void setProgressHeight(int height) {        mHeight = height;    }    public synchronized void setMax(int max) {        if (max < 0) {            throw new IllegalArgumentException("max不能小于0");        }        this.max = max;    }    public void setRoundColor(int roundColor) {        this.roundColor = roundColor;    }    public void setRoundWidth(float roundWidth) {        this.roundWidth = roundWidth;    }    public void setRoundProgressColor(int roundProgressColor) {        this.roundProgressColor = roundProgressColor;    }    public void setTextSize(float textSize) {        this.textSize = textSize;    }    public void setTextColor(int textColor) {        this.textColor = textColor;    }    public void setTextShow(boolean textShow) {        this.textShow = textShow;    }    public synchronized void setProgress(int progress) {        if (progress < 0) {            throw new IllegalArgumentException("progress不能小于0");        }        if (progress > max) {            progress = max;        }        if (progress <= max) {            this.progress = progress;            postInvalidate();        }    }    public synchronized int getMax() {        return max;    }    public int getRoundColor() {        return roundColor;    }    public float getRoundWidth() {        return roundWidth;    }    public int getRoundProgressColor() {        return roundProgressColor;    }    public int getTextColor() {        return textColor;    }    public boolean isTextShow() {        return textShow;    }    public synchronized int getProgress() {        return progress;    }}复制代码

流程:初始化的时候会拿到自定义属性,然后onMeasure方法中测量控件的宽和高,该方法主要处理了LayoutParams的wrap_content,当wrap_content时,默认设置默认宽/高,而不是让控件占据整个屏幕,需要调用setMeasuredDimension方法测量。最后测量得到了控件的宽/高,调用onDraw方法将界面绘制到屏幕上,在onDraw方法绘制的时需要考虑padding的情况,如果不做padding处理,则padding将不起作用。

onDraw绘制流程:先绘制一个默认的大圆环,然后在圆中心绘制百分比的文本,最后再绘制一个进度圆环,进度圆环会覆盖底部的默认大圆环,这样就达到显示进度的情况。

设置好画笔之后,使用canvas.drawCircle绘制默认的大圆环,再次设置画笔,使用canvas.drawText方法绘制文本;画圆弧时需要定义一个矩形区域RectF,通过canvas.drawArc方法绘制。

绘制好之后,如何让用户看到进度条在变化呢?其实就是通过setProgress方法里面的postInvalidate()方法,该方法会刷新界面,刷新界面时会调用onDraw,这样就可以将进度画到屏幕上,进度条不停的在变化。

使用

XML中使用

复制代码

Activity代码如下:

public class PaintActivity extends AppCompatActivity {    private CustomProgressBar mCustomProgressBar;    private CustomProgressBar mCustomProgressBar01;    private int progress;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_paint);        mCustomProgressBar = (CustomProgressBar)this.findViewById(R.id.progressbar);        mCustomProgressBar.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                new Thread(new Runnable() {                    @Override                    public void run() {                        progress = 0;                        while (progress <= 100) {                            progress += 2;                            mCustomProgressBar.setProgress(progress);                            try {                                Thread.sleep(100);                            } catch (InterruptedException e) {                                e.printStackTrace();                            }                        }                    }                }).start();            }        });        mCustomProgressBar01 = (CustomProgressBar)this.findViewById(R.id.progressbar01);        mCustomProgressBar01.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                new Thread(new Runnable() {                    @Override                    public void run() {                        progress = 0;                        while (progress <= 100) {                            progress += 2;                            mCustomProgressBar01.setProgress(progress);                            try {                                Thread.sleep(100);                            } catch (InterruptedException e) {                                e.printStackTrace();                            }                        }                    }                }).start();            }        });    }}复制代码

这样就完成了一个自定义的进度条控件,并且在onDraw方法中使用Paint将界面绘制出来。读者可以自行实践一把,加深对Paint的理解。

转载地址:http://wfbnl.baihongyu.com/

你可能感兴趣的文章
[学习笔记]猫树
查看>>
iphone-common-codes-ccteam源代码 CCPoint.h
查看>>
转载:python文件打开方式详解——a、a+、r+、w+区别
查看>>
一道js试题
查看>>
Mac中文乱码问题
查看>>
TOJ 2710: 过河 路径压缩
查看>>
[PE484]Arithmetic Derivative
查看>>
增加XMLDoc对IE 11的支持
查看>>
[原创]Matlab2016b打包为C++的lib文件
查看>>
字符串转化为数值
查看>>
翻转链表问题
查看>>
Rapid Publication
查看>>
JavaScript之JSON
查看>>
linux剪切拷贝
查看>>
isinstance, type, issubclass
查看>>
[扫雷][游戏] 交互*2
查看>>
Python函数
查看>>
python 开发技巧(4)-- 用PyCharm实用技巧(我自己常用的)
查看>>
Path Sum II
查看>>
[转载]STM32高级定时器(TIM1和TIM8)、通用定时器(TIMx) 、 基本定时器(TIM6和TIM7)的区别...
查看>>