自定义控件,动画效果的进度圆环RingProgressBar

本文介绍了一种自定义的环形进度条RingProgressBar,通过继承View类实现,并利用SweepGradient渲染器实现扇形颜色渐变效果。提供了设置起始、中间和结束颜色的功能,以及最大值和进度值的自定义属性。

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

自定义动画效果的进度圆环RingProgressBar

项目中有一个进度圆环,实现一个比例的显示,原生的ProgressBar就算自定义样式也不是很美观,于是就自定义了一个,继承于View类,效果如下:

动画效果图


代码

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.SweepGradient;
import android.os.Handler;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;

/**
 * 环形进度条
 * Created by Wood on 2016/7/21.
 */
public class RingProgressBar extends View {
    private static final String LOG_TAG = "RingProgressBar";

    /**
     * 总值
     */
    private double max = 100;
    /**
     * 已使用
     */
    private double progress = 0;
    /**
     * 目标比例
     */
    private double aimAngle;
    /**
     * 进度条画笔
     */
    private Paint mPaint;
    private int strokeWidth = 12;
    private int wh;
    private int center;
    private int radius;
    private RectF oval;
    private Handler handler = new Handler();
    private int angle = -1;
    /**
     * 着色器,这里使用了一个扫描渲染器(SweepGradient)实现渐变色
     */
    private Shader shader;
    /**
     * 刻度背景图
     */
    private Bitmap bitmapBackground;

    /**
     * 开始的颜色
     */
    private int startColor = Color.parseColor("#303F9F");//开始颜色
    /**
     * 中间的颜色
     */
    private int centerColor = Color.parseColor("#FF4081");//中间颜色
    /**
     * 结束的颜色
     */
    private int endColor = Color.parseColor("#303F9F");//开始颜色

    /**
     * 进度条颜色数组
     */
    private int[] colors = new int[]{
            startColor,
            centerColor,
            endColor
    };
    /**
     * 刻度缩放比率
     */
    private float ratio = 1;

    public RingProgressBar(Context context) {
        this(context, null);
    }

    public RingProgressBar(Context context, AttributeSet attrs) {
        super(context, attrs);
        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.RingProgressBar);
        startColor = a.getColor(R.styleable.RingProgressBar_startColor, startColor);
        centerColor = a.getColor(R.styleable.RingProgressBar_centerColor, centerColor);
        endColor = a.getColor(R.styleable.RingProgressBar_endColor, endColor);
        max = (double) a.getFloat(R.styleable.RingProgressBar_max, (float) max);
        progress = (double) a.getFloat(R.styleable.RingProgressBar_progress, (float) progress);
        a.recycle();
        colors = new int[]{startColor, centerColor, endColor};
        init();
        setValue(max, progress);
    }

    private void init() {
        bitmapBackground = BitmapFactory.decodeResource(getResources(), R.mipmap.dial);
        strokeWidth = dip2px(12);

        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeWidth(strokeWidth);
        mPaint.setStrokeCap(Paint.Cap.ROUND);

        aimAngle = -1;
    }

    /**
     * 画进度环,这里控制圆环的动画速度,可以调整一个合适的速度
     */
    Runnable runnable = new Runnable() {
        @Override
        public void run() {
            angle += 6;
            if (angle <= aimAngle) {
                postInvalidate();
                handler.postDelayed(runnable, 3);
            }
        }
    };

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (progress > 0) {
            canvas.drawArc(oval, -90, angle, false, mPaint);
        }
        //根据空间大小缩放刻度背景图片
        Matrix matrix = new Matrix();
        matrix.postScale(ratio, ratio);
        Bitmap bmp = Bitmap.createBitmap(bitmapBackground, 0, 0, bitmapBackground.getWidth(), bitmapBackground.getHeight(), matrix, true);
        canvas.drawBitmap(bmp, 0, 0, mPaint);
    }


    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int width = MeasureSpec.getSize(widthMeasureSpec);
        int height = MeasureSpec.getSize(heightMeasureSpec);

        Log.e(LOG_TAG, "width:" + width + "...height:" + height);
        Log.e(LOG_TAG, "bitmapBackground.width:" + bitmapBackground.getWidth() + "...bitmapBackground.height:" + bitmapBackground.getHeight());

        wh = Math.min(width, height);
        if (bitmapBackground.getWidth() != 0 && wh != 0) {
            ratio = (float) wh / (float) bitmapBackground.getWidth();
        }
        center = wh / 2;
        radius = center - strokeWidth / 2;
        oval = new RectF(center - radius, center - radius, center + radius, center + radius);
        shader = new SweepGradient(center, center, colors, null);
        Matrix m = new Matrix();
        m.setRotate(-90, center, center);
        shader.setLocalMatrix(m);
        mPaint.setShader(shader);
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    /**
     * 释放bitmap资源
     */
    public void clearBitmap() {
        if (bitmapBackground != null && !bitmapBackground.isRecycled()) {
            bitmapBackground.recycle();
        }
    }

    /**
     * 设置目标比率
     *
     * @param max
     * @param progress
     */
    public void setValue(double max, double progress) {
        this.max = max;
        this.progress = progress;
        if (max != 0f) {
            aimAngle = progress / max * 360;
        }
        angle = -1;
        handler.postDelayed(runnable, 400);//这里延时一下执行,有时候页面加载延时可能看不到动画
    }

    /**
     * 获取最大进度,默认100
     *
     * @return
     */
    public double getMax() {
        return max;
    }

    /**
     * 设置最大进度
     *
     * @param max
     */
    public void setMax(double max) {
        if (max > 0) {
            this.max = max;
        }
    }

    /**
     * 获取当前进度,默认0
     *
     * @return
     */
    public double getProgress() {
        return progress;
    }

    /**
     * 设置当前进度
     *
     * @param progress
     */
    public void setProgress(double progress) {
        if (progress >= 0) {
            this.progress = progress;
        }
        if (max >= 0 && max >= progress) {
            setValue(max, progress);
        }
    }

    /**
     * dp转px
     *
     * @param dip
     * @return
     */
    private int dip2px(float dip) {
        float density = getContext().getResources().getDisplayMetrics().density;
        int px = (int) (dip * density + 0.5f);
        return px;
    }
}

自定义属性

设置起始中间和结束的颜色,使用SweepGradient渲染器,实现扇形的颜色渐变,如果想自己定制更多颜色,可以改变代码里的数组,在这里只提供三种颜色设置。还提供最大值和进度值
的设置。也可通过程序里的set方法设置颜色和进度信息。

<!-- RingProgressBar -->
    <declare-styleable name="RingProgressBar">
        <attr name="startColor" format="color" />
        <attr name="centerColor" format="color" />
        <attr name="endColor" format="color" />
        <attr name="max" format="float" />
        <attr name="progress" format="float" />
    </declare-styleable>

刻度图片资源

这个图片大小是固定的,虽然程序里做了适配,但是控件太大或太小多少会有点失真,所以尽量控制在图片大小的尺寸比较好,当然看着舒服就好。

图片在下面


刻度图片资源,有点透明,设个背景色就看见了


图片在上面

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值