自定义进度条(1)

最近写了两个自定义进度条,一个静态的,一个带动画的,都比较简单,直接继承View,但是带动画的进度条应该还有更好的实现方法,如果有大神路过就指点一下吧!


静态的ProgressView,要求进度条的进度头部,带一个百分数,说明现在到达百分之几,效果图如下:


进度条上方文字不超出进度条两侧,其次,进度条上方文字的中间与进度条头部对齐。


我来分解一下,这里有三部分,第一部分是文字,我们使用一个TextPaint来画,第二第三部分是paogress的前景与后景。

然后是作图,首先我们要获取各种数据。

横向:屏幕宽度、文字宽度

纵向:文字高度、进度条高度以及两者间隙

确定需要的变量或常量:

    private float progress;

    private TextPaint textPaint;
    private float textHeight;

    private float textProgressPadding;

    private Paint backgroundPaint, foregroundPaint;
    private float progressHeight;

    private DecimalFormat df;

numberWidth是三个固定的宽度,在初始化的时候就算好。


设置一个初始化方法:

    private void initView() {
        textHeight = DisplayUtils.sp2px(getContext(), 13f);
        textProgressPadding = DisplayUtils.dip2px(getContext(), 3f);
        progressHeight = DisplayUtils.dip2px(getContext(), 2.5f);

        textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
        textPaint.setColor(0xffff9600);
        textPaint.setTextSize(textHeight);

        foregroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        foregroundPaint.setColor(0xffff9600);
        foregroundPaint.setStyle(Paint.Style.FILL);

        backgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        backgroundPaint.setColor(0xffeeeeee);
        backgroundPaint.setStyle(Paint.Style.FILL);

        df = new DecimalFormat("0.00");
        progress = 0;
    }

除2是为了获取半宽,因为要把文字居中(文字绘制是从x=0,y=baseline处开始的,这三个数字针对的是x方向)


View的绘制过程是onMeasure,onLayout,onDrwa,而onMeasure完成后我们就可以直接通过getWidth()获取屏幕宽度了。

好,我们先完成onMeasure,这里宽度随屏幕,高度写死:

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int width, height;

        if (widthMode == MeasureSpec.EXACTLY) {
            width = widthSize;
        } else {
            width = getSuggestedMinimumWidth();
        }
        height = (int) Math.ceil(textHeight + textProgressPadding + progressHeight);
        setMeasuredDimension(width, height);
    }

然后完成onDraw:

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        Paint.FontMetrics fontMetrics = textPaint.getFontMetrics();
        float currentProgressWidth = getWidth() * progress / 100;

        String progressStr = df.format(progress) + "%";
        float halfTextWidth = textPaint.measureText(progressStr) / 2;

        if (currentProgressWidth < halfTextWidth) {//左对齐
            canvas.drawText(progressStr, 0, -fontMetrics.ascent, textPaint);
        } else if (getWidth() - currentProgressWidth < halfTextWidth) {//右对齐
            canvas.drawText(progressStr, getWidth() - halfTextWidth * 2, -fontMetrics.ascent, textPaint);
        } else {//居中
            canvas.drawText(progressStr, currentProgressWidth - halfTextWidth, -fontMetrics.ascent, textPaint);
        }

        canvas.drawRect(
                0,
                textHeight + textProgressPadding,
                getWidth(),
                textHeight + textProgressPadding + progressHeight,
                backgroundPaint
        );

        canvas.drawRect(
                0,
                textHeight + textProgressPadding,
                currentProgressWidth,
                textHeight + textProgressPadding + progressHeight,
                foregroundPaint
        );
    }


FrontMetrics可以获取文字的各种高度宽度,ascent就是baseline以上的高度,不过它取出来的时候是个负数。

上面if-else的逻辑是:左边尽头,进度条宽度小于文字半宽,文字就靠左贴边,右边尽头,进度条所剩宽度小于文字半宽,文字就靠右贴边,不满足以上判断条件的就居中(计算的时候分两种情况:0.0%,00.0%)。


最后,加上progress的set方法,达到100的时候让它变红,不是100的时候都是橙色:

   public void setProgress(float progress) {
        if (progress < 0) progress = 0;
        if (progress >= 100) {
            //progress = 100;
            textPaint.setColor(0xfff74b4b);
            foregroundPaint.setColor(0xfff74b4b);
        } else {
            textPaint.setColor(0xffff9600);
            foregroundPaint.setColor(0xffff9600);
        }
        this.progress = (float)(Math.round(progress*100))/100;//保留两位小数
        invalidate();
    }


还有构造方法:

    public SuperDaTaoProgress(Context context) {
        super(context);
        initView();
    }

    public SuperDaTaoProgress(Context context, AttributeSet attrs) {
        super(context, attrs);
        initView();
    }

动态的下一篇讲,也是比较简单的



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,关于 Android 自定义进度条控件的实现,我可以为您提供一些思路和示例代码。 首先,我们需要继承自 View 或者 ProgressBar,然后在 onDraw 方法中实现自己的绘制逻辑。具体来说,需要绘制背景、进度条和文本等内容。 示例代码如下: ```java public class CustomProgressBar extends ProgressBar { private Paint mPaint; private String mText; private Rect mRect; public CustomProgressBar(Context context) { super(context); init(); } public CustomProgressBar(Context context, AttributeSet attrs) { super(context, attrs); init(); } public CustomProgressBar(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(); } private void init() { mPaint = new Paint(); mPaint.setAntiAlias(true); mRect = new Rect(); } @Override protected synchronized void onDraw(Canvas canvas) { super.onDraw(canvas); // 绘制背景 mPaint.setColor(Color.GRAY); mPaint.setStyle(Paint.Style.FILL); canvas.drawRect(0, 0, getWidth(), getHeight(), mPaint); // 绘制进度条 mPaint.setColor(Color.BLUE); mPaint.setStyle(Paint.Style.FILL); float progress = getProgress() * 1.0f / getMax(); canvas.drawRect(0, 0, getWidth() * progress, getHeight(), mPaint); // 绘制文本 mPaint.setColor(Color.WHITE); mPaint.setTextSize(24); mText = getProgress() + "%"; mPaint.getTextBounds(mText, 0, mText.length(), mRect); float x = getWidth() / 2f - mRect.centerX(); float y = getHeight() / 2f - mRect.centerY(); canvas.drawText(mText, x, y, mPaint); } } ``` 这个自定义控件实现了一个简单的水平进度条,包括了背景、进度条和文本三个部分。当然,您可以根据自己的需求进行更改和扩展。 希望这个示例代码能够帮助到您,如果您还有其他问题,欢迎继续提问。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值