android打造酷炫自定义ProgressBar

来源:互联网 发布:php log打印到日志 编辑:程序博客网 时间:2024/05/25 21:33

自定义控件分三步:

1.自定义属性的声明与获取:

(1)找到value文件夹,新建一个名为attrs的xml文件:

由图可以看出:需要打造的水平进度条的progressbar需要有哪些自定义属性呢?基本需要七个属性:

a.左边已完成的进度reachbar需要高度reachbarheight

b.左边已完成的进度reachbar需要颜色reachbarcolor

c.中间的文字需要大小textsize

d.中间的文字需要颜色textcolor

e.中间的文字需要与Bar之间的间隔textoffset

f.右边未完成的进度unreachbar需要颜色unreachbarcolor

g.右边未完成的进度unreachbar需要高度unreachbarheight

所以我们需要对这七个属性进行声明

<attr name="progress_unreach_color" format="color"></attr><attr name="progress_unreach_height" format="dimension"></attr><attr name="progress_reach_color" format="color"></attr><attr name="progress_reach_height" format="dimension"></attr><attr name="progress_text_size" format="dimension"></attr><attr name="progress_text_color" format="color"></attr><attr name="progress_text_offset" format="dimension"></attr>

声明后,我们需要新建一个继承自ProgressBar 的view命名为HorizontalProgressbar,然后在attrs文件中的declare-styleable标签中进行使用:

<declare-styleable name="HorizontalProgressBar">    <attr name="progress_unreach_color" ></attr>    <attr name="progress_unreach_height" ></attr>    <attr name="progress_reach_color" ></attr>    <attr name="progress_reach_height" ></attr>    <attr name="progress_text_size" ></attr>    <attr name="progress_text_color" ></attr>    <attr name="progress_text_offset" ></attr></declare-styleable>
(2)获取自定义属性:

private void obtainStyledattrs(AttributeSet attrs) {    TypedArray ta=getContext().obtainStyledAttributes(attrs,R.styleable.HorizontalProgressBar);    mTextSize=(int)ta.getDimension(R.styleable.HorizontalProgressBar_progress_text_size,mTextSize);    mTextColor=ta.getColor(R.styleable.HorizontalProgressBar_progress_text_color,mTextColor);    mTextOffset=(int)ta.getDimension(R.styleable.HorizontalProgressBar_progress_text_offset,mTextOffset);    mReachColor=ta.getColor(R.styleable.HorizontalProgressBar_progress_reach_color,mReachColor);    mReachHeight=(int)ta.getDimension(R.styleable.HorizontalProgressBar_progress_reach_height,mReachHeight);    mUnReachColor=ta.getColor(R.styleable.HorizontalProgressBar_progress_unreach_color,mUnReachColor);    mUnReachHeight=(int)ta.getDimension(R.styleable.HorizontalProgressBar_progress_unreach_height,mUnReachHeight);    ta.recycle();}

2.控件的测量onMeasure()

onMeasure(widthMeasureSpec,heightMeasureSpec)方法中我们需要得到控件的宽高的模式,以及它的具体值,

int widthMode=MeasureSpec.getMode(widthMeasureSpec);int widthVal=MeasureSpec.getSize(widthMeasureSpec);
得到测量模式之后,与三种模式相比较,如果模式是EXACTLY,也就是说用户给的是准确值的话,那么就直接将用户给定的结果作为测量值,如果是其他两种模式,那么就需要自己去测量控件的值,由图可知,整个控件的高度是由ReachBar和Text以及UnReachBar三者高度的最大值来决定,这就要求我们对Text的值进行测量,Text的值可以通过画笔的descent和ascent来测量。此处贴上代码:

private int measureHeight(int heightMeasureSpec) {    int result=0;    int heightMode=MeasureSpec.getMode(heightMeasureSpec);    int heightSize=MeasureSpec.getSize(heightMeasureSpec);    if (heightMode==MeasureSpec.EXACTLY){        //如果用户给定了精确值,那么就直接给将heightSize设置为测量值        result=heightSize;    }else {        //如果是其他两种模式,        int textHeight=(int) (mPaint.descent()-mPaint.ascent());        result=getPaddingTop()+getPaddingBottom()+Math.max(Math.max(mReachHeight,mUnReachHeight),Math.abs(textHeight));        if (heightMode==MeasureSpec.AT_MOST){            result=Math.min(result,heightSize);        }    }    return result;}
最后就是要将测量后的宽高重新设置给控件:

@Overrideprotected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {    int widthMode=MeasureSpec.getMode(widthMeasureSpec);    int widthVal=MeasureSpec.getSize(widthMeasureSpec);    int height=measureHeight(heightMeasureSpec);    setMeasuredDimension(widthVal,height);    mRealWidth=getMeasuredWidth()-getPaddingLeft()-getPaddingRight();}
3.绘制控件onDraw()方法

根据属性分别绘制控件中的三部分,reachBar,UnReachBar和text

@Overrideprotected synchronized void onDraw(Canvas canvas) {    canvas.save();    canvas.translate(getPaddingLeft(),getHeight()/2);    boolean noNeedUnReach=false;    float radio=getProgress()*1.0f/getMax();    //得到文本的宽度    String text=getProgress()+"%";    int textWidth=(int)mPaint.measureText(text);    float progressX=radio*mRealWidth;    if (progressX+textWidth>mRealWidth){        progressX=mRealWidth-textWidth;        noNeedUnReach=true;    }    float endX=radio*mRealWidth-mTextOffset/2;//reachBar的绘制结尾    if (endX>0){        mPaint.setColor(mReachColor);        mPaint.setStrokeWidth(mReachHeight);        canvas.drawLine(0,0,endX,0,mPaint);    }    //draw text    mPaint.setColor(mTextColor);    int y=(int)(-(mPaint.descent()+mPaint.ascent())/2);    canvas.drawText(text,progressX,y,mPaint);    //draw UnReachBar    if (!noNeedUnReach){        float start=progressX+textWidth+mTextOffset/2;        mPaint.setColor(mUnReachColor);        mPaint.setStrokeWidth(mUnReachHeight);        canvas.drawLine(start,0,mRealWidth,0,mPaint);    }    canvas.restore();}
这就是自定义控件的三个流程,最后在测试一下就完美了;

其中的进度条的颜色和文本颜色高度都可以控制。