Android 实现渐变色的交替圆弧,显示进度百分比

前段时间无事水群,发现有个哥们要实现这么一个需求
这里写图片描述
仔细一看,与可以显示当前进度度的交替圆环不同的是,第二段圆弧的颜色是渐变的。既然无事,那就解决掉吧。
先声明自定义属性

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="ColorfulRing">
        <attr name="major_color" format="color"/>
        <attr name="secondary_color" format="color"/>
        <attr name="radius" format="dimension"/>
        <attr name="arc_width" format="dimension"/>
        <attr name="text_size" format="dimension"/>
        <attr name="current_value" format="integer"/>
        <attr name="max_value" format="integer"/>
    </declare-styleable>
</resources>

接下来是自定义view

public class ColorfulRing extends View {
    private  String mTextContent;
    private int mMajorColor;//主颜色
    private int mSecondaryColor;//次颜色
    private int mRadius;//半径
    private int mCurrentValue;//当前值
    private int mMaxValue;//最大值
    public Paint mPaint;
    public int mArcWidth;//环宽
    public int mHeight;
    public int mWidth;
    public int WIDTH_BLANK;//横向空白
    public int HEIGHT_BLANK;//纵向空白
    public float mTextDimen;//文字尺寸
    private Rect mTextBounds;

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

    public ColorfulRing(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public ColorfulRing(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        //获取自定义属性
        TypedArray arrayAttr = context.getTheme().obtainStyledAttributes(attrs, R.styleable.ColorfulRing, defStyleAttr, 0);
        int num = arrayAttr.getIndexCount();
        for (int i = 0; i < num; i++) {//筛选目的属性
            int attr = arrayAttr.getIndex(i);
            switch (attr) {
                case R.styleable.ColorfulRing_major_color:
                    mMajorColor = arrayAttr.getColor(attr, Color.BLACK);
                    break;
                case R.styleable.ColorfulRing_secondary_color:
                    mSecondaryColor = arrayAttr.getColor(attr, Color.WHITE);
                    break;
                case R.styleable.ColorfulRing_current_value:
                    mCurrentValue = arrayAttr.getInt(attr, 0);
                    break;
                case R.styleable.ColorfulRing_max_value:
                    mMaxValue = arrayAttr.getInt(attr, 0);
                    break;
                case R.styleable.ColorfulRing_radius:
                    mRadius = (int) arrayAttr.getDimension(attr, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
                            100, getResources().getDisplayMetrics()));
                    break;
                case R.styleable.ColorfulRing_text_size:
                    mTextDimen = arrayAttr.getDimension(attr, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,
                            12, getResources().getDisplayMetrics()));
                    break;
            }
        }
        arrayAttr.recycle();
        //创造画笔
        mPaint = new Paint();
        mPaint.setAntiAlias(true);//抗锯齿
        mPaint.setStrokeCap(Paint.Cap.ROUND);//绘制的结尾是圆弧
        //环的宽度取半径的1/8
        mArcWidth = mRadius / 8;
        WIDTH_BLANK = 2 * mArcWidth;
        HEIGHT_BLANK = 2 * mArcWidth;
        //文本渲染区域
        mTextBounds = new Rect();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        //宽度模式必须设定为wrap_content,只需设置半径值就可以确定范围
        mWidth = 2 * mRadius + 4 * mArcWidth + WIDTH_BLANK;
        mHeight = mRadius + mArcWidth + mArcWidth + HEIGHT_BLANK;
        setMeasuredDimension(mWidth, mHeight);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        mPaint.setStrokeWidth(mArcWidth);//设置环的宽度
        mPaint.setStyle(Paint.Style.STROKE);//空心

        int centerX = mWidth / 2;
        //确定圆弧绘制范围
        RectF oval = new RectF(centerX - mRadius, HEIGHT_BLANK / 2 + mArcWidth, centerX + mRadius, HEIGHT_BLANK / 2 + mArcWidth + 2 * mRadius);
        mPaint.setColor(mMajorColor);
        canvas.drawArc(oval, 180, 180, false, mPaint);
        //绘制代表当前进度的弧线
        double percent = mCurrentValue * 1.0 / mMaxValue;
        int currentArc = (int) (180 * percent);
        int edgeX = (int) (mRadius + mRadius * Math.cos(Math.toRadians(180 - currentArc)));//计算当前进度圆弧在X轴上的偏移量
        Shader mShader = new LinearGradient(centerX - mRadius - mArcWidth / 2, 0, centerX - mRadius + edgeX + mArcWidth, 0,
                new int[]{mMajorColor, mSecondaryColor}, null, Shader.TileMode.REPEAT);//centerX-mRadius+edgeX+mArcWidth,为了保证圆弧尾端的颜色不被覆盖
        mPaint.setShader(mShader);
        canvas.drawArc(oval, 180, currentArc, false, mPaint);
        //绘制弧底部的基线
        mPaint.setShader(null);//清除渐变色
        mPaint.setColor(mMajorColor);
        canvas.drawLine(centerX - mRadius - mArcWidth, HEIGHT_BLANK / 2 + mRadius + mArcWidth+mArcWidth/2, centerX + mRadius + mArcWidth, HEIGHT_BLANK / 2 + mRadius + mArcWidth+mArcWidth/2, mPaint);
        //绘制文字
        mTextContent=mCurrentValue*100/mMaxValue+"%";//拼装待绘制文字
        mPaint.setTextSize(mTextDimen);//必须在测量mTextBounds之前执行
        mPaint.getTextBounds(mTextContent, 0, mTextContent.length(), mTextBounds);
        mPaint.setColor(mMajorColor);

        mPaint.setStyle(Paint.Style.FILL);
        mPaint.setAntiAlias(true);//抗锯齿
        //居中显示
        canvas.drawText(mTextContent,(mWidth-mTextBounds.width())*1.0f/2,mRadius,mPaint);
    }

    public void setCurrentValue(int currentValue) {
        mCurrentValue = currentValue;
        postInvalidate();//重新绘制
    }

    public void setMaxValue(int maxValue) {
        mMaxValue = maxValue;
        postInvalidate();//重新绘制
    }
}

最后是在布局文件中使用

<com.example.bigyoung.colorfulring.view.ColorfulRing
        android:layout_height="wrap_content"
        android:layout_width="wrap_content"
        app:radius="130dp"
        app:major_color="#25a708"
        app:secondary_color="#35C4EABC"
        app:current_value="600"
        app:max_value="900"
        app:text_size="20sp"
        >
    </com.example.bigyoung.colorfulring.view.ColorfulRing>

因为偷懒的原因,在这里没有考虑padding值,自定义属性arc_width在代码中设定,各位看官可根据自己的需求自行修改。关键性的地方代码中已有详细注释。
如果你觉得这篇文章对你有用,那么赞一个吧<3<3
源码下载

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值