android打造酷炫自定义ProgressBar

本文介绍了如何在Android中创建自定义水平进度条,包括声明和获取自定义属性,如高度、颜色、字体大小等,并详细讲解了在onMeasure()方法中测量并绘制已完成和未完成进度条以及文字的步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

自定义控件分三步:

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;
}
最后就是要将测量后的宽高重新设置给控件:

@Override
protected 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

@Override
protected 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();
}
这就是自定义控件的三个流程,最后在测试一下就完美了;

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





























评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值