Android自定义圆环百分比控件

这是RoundView

package com.basic.security.widget;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
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.support.annotation.Nullable;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Transformation;

import com.basic.security.R;

/**
 * 自定义圆环(设置集群页面)
 */
public class RoundView extends View implements Animation.AnimationListener {

    /**
     * 圆环转过的角度
     */
    private float mSweepAngle = 1;
    /**
     * 之前的角度
     */
    private float mOldAngle = 0;
    /**
     * 新的角度
     */
    private float mNewAngle = 0;
    /**
     * 圆环宽度,默认半径的1/5
     */
    private float mRingWidth = 0;
    /**
     * 圆环颜色,默认 #CBCBCB
     */
    private int mRingColor = 0;
    /**
     * 进度条圆环宽度
     */
    private float mProgressRingWidth = 0;
    /**
     * 进度条圆环开始颜色,进度条圆环是渐变的,默认
     */
    private int mProgressRingStartColor = 0;
    /**
     * 进度条圆环结束颜色,进度条圆环是渐变的,默认
     */
    private int mProgressRingEndColor = 0;
    /**
     * 圆环半径,默认:Math.min(getHeight()/2,getWidth()/2)
     */
    private float mRadius = 0;
    /**
     * 进度条圆环Paint
     */
    private Paint mProgressRingPaint;
    /**
     * 进度条圆环渐变shader
     */
    private Shader mProgressRingShader;

    /**
     * 底环画笔
     */
    private Paint mRingPaint;
    /**
     * 文字画笔
     */
    private Paint mTextPaint;
    /**
     * 文字颜色
     */
    private int mTextColor;
    /**
     * 文字大小
     */
    private float mTextSize;

    private int[] arcColors = {};// 渐变色
    /**
     * 进度动画
     */
    private BarAnimation barAnimation;
    /**
     * 抖动(缩放)动画
     */
    private ScaleAnimation scaleAnimation;
    /**
     * 是否正在改变
     */
    private boolean isAnimation = false;

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

    public RoundView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);

    }

    public RoundView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        this(context, attrs, defStyleAttr, 0);
    }

    public RoundView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr);

        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.RoundView);
        mRingWidth = typedArray.getDimension(R.styleable.RoundView_ring_width, 0);
        mRingColor = typedArray.getColor(R.styleable.RoundView_ring_color, Color.parseColor("#CBCBCB"));
        mProgressRingWidth = typedArray.getDimension(R.styleable.RoundView_progress_ring_width, 0);
        mProgressRingStartColor = typedArray.getColor(R.styleable.RoundView_progress_ring_start_color, Color.parseColor("#086ab5"));
        mProgressRingEndColor = typedArray.getColor(R.styleable.RoundView_progress_ring_end_color, Color.parseColor("#21cbe2"));
        mRadius = typedArray.getDimension(R.styleable.RoundView_android_radius, 0);
        mTextColor = typedArray.getColor(R.styleable.RoundView_text_color, Color.parseColor("#086ab5"));
        mTextSize = typedArray.getDimension(R.styleable.RoundView_text_size, dp2px(context, 40));
        typedArray.recycle();
        init();
    }

    /**
     * 初始化
     */
    private void init() {

        mRingPaint = new Paint();
        mRingPaint.setAntiAlias(true);// 抗锯齿效果
        mRingPaint.setStyle(Paint.Style.STROKE);
        mRingPaint.setColor(mRingColor);// 背景灰

        // 圆环紫色渐变色
        arcColors = new int[]{mProgressRingStartColor, mProgressRingEndColor};
        mProgressRingPaint = new Paint();
        mProgressRingPaint.setAntiAlias(true);// 抗锯齿效果
        mProgressRingPaint.setStyle(Paint.Style.STROKE);
        mProgressRingPaint.setStrokeWidth(mProgressRingWidth);

        mTextPaint = new Paint();
        mTextPaint.setAntiAlias(true);// 抗锯齿效果
        mTextPaint.setStyle(Paint.Style.FILL);
        mTextPaint.setTextAlign(Paint.Align.CENTER);
        mTextPaint.setColor(mTextColor);// 字体颜色
        mTextPaint.setTextSize(mTextSize);


        barAnimation = new BarAnimation();
        barAnimation.setAnimationListener(this);

        scaleAnimation = new ScaleAnimation();
        scaleAnimation.setDuration(100);
    }

    /**
     * 设置新的角度
     * newAngle:角度
     */
    public void setAngle(final float newAngle) {
        setAngle(newAngle, true);
    }

    /**
     * 设置新的角度
     * newAngle:角度
     * isScale:是否抖动
     */
    public void setAngle(final float newAngle, boolean isScale) {
        if (!isAnimation) {
            if (isScale) {
                scaleAnimation.setAnimationListener(new Animation.AnimationListener() {
                    @Override
                    public void onAnimationStart(Animation animation) {

                    }

                    @Override
                    public void onAnimationEnd(Animation animation) {
                        changeAngle(newAngle);
                    }

                    @Override
                    public void onAnimationRepeat(Animation animation) {

                    }
                });
                startAnimation(scaleAnimation);
            } else {
                changeAngle(newAngle);
            }
        }
    }


    private void changeAngle(float newAngle) {
        mOldAngle = mNewAngle;
        mNewAngle = newAngle;
        //计算动画时间
        int duration = (int) (Math.abs(mNewAngle - mOldAngle) * 15);
        barAnimation.setDuration(duration);
        //动画差值器
        barAnimation.setInterpolator(new DecelerateInterpolator());
        startAnimation(barAnimation);
    }

    @SuppressLint("DrawAllocation")
    @Override
    public void onDraw(Canvas canvas) {

        // 圆心坐标,当前View的中心
        float x = getWidth() / 2;
        float y = getHeight() / 2;

        //如果未设置半径,则半径的值为view的宽、高一半的较小值
        float radius = mRadius == 0 ? Math.min(getWidth() / 2, getHeight() / 2) : mRadius;
        //圆环的宽度默认为半径的1/5
        float ringWidth = mRingWidth == 0 ? radius / 5 : mRingWidth;
        //由于圆环本身有宽度,所以半径要减去圆环宽度的一半,不然一部分圆会在view外面
        radius = radius - ringWidth / 2;
        mRingPaint.setStrokeWidth(ringWidth);

        // 底环
        canvas.drawCircle(x, y, radius, mRingPaint);
        //----绘制圆环(最底部)结束------

        //----绘制进度圆环------
        // 设置渐变色
        if (mProgressRingShader == null) {
            mProgressRingShader = new SweepGradient(x, y, arcColors, null);
            mProgressRingPaint.setShader(mProgressRingShader);
        }
        //计算进度圆环宽度,默认和底部圆滑一样大
        float progressRingWidth = mProgressRingWidth == 0 ? ringWidth : mProgressRingWidth;
        mProgressRingPaint.setStrokeWidth(progressRingWidth);
        float left = x - radius;
        float top = y - radius;
        float right = x + radius;
        float bottom = y + radius;
        // 旋转画布90度+笔头半径转过的角度
        double radian = radianToAngle(radius);
        double degrees = Math.toDegrees(-2 * Math.PI / 360 * (90 + radian));// 90度+
        canvas.save();
        canvas.rotate((float) degrees, x, y);
        canvas.drawArc(new RectF(left, top, right, bottom), (float) radian, mOldAngle + mSweepAngle, false, mProgressRingPaint);
        canvas.restore();
        //----绘制进度圆环结束------


        //----绘制百分比字体开始------

        int percentage = (int) ((mOldAngle + mSweepAngle) / 360 * 100);
        float sizeHeight = getFontHeight();
        canvas.drawText(percentage + "%", x, y + sizeHeight / 2, mTextPaint);

        //----绘制百分比字体结束------
        super.onDraw(canvas);
    }

    public float getFontHeight() {
        Paint.FontMetrics fm = mTextPaint.getFontMetrics();
        return fm.descent - fm.ascent;
    }

    /**
     * 已知圆半径和切线长求弧长公式
     *
     * @param radios
     * @return
     */
    private double radianToAngle(float radios) {
        double aa = mProgressRingWidth / 2 / radios;
        double asin = Math.asin(aa);
        double radian = Math.toDegrees(asin);
        return radian;
    }


    /**
     * 抖动(缩放动画)
     */
    public class ScaleAnimation extends Animation {
        private int centerX;
        private int centerY;

        public ScaleAnimation() {
        }

        @Override
        public void initialize(int width, int height, int parentWidth,
                               int parentHeight) {
            super.initialize(width, height, parentWidth, parentHeight);
            centerX = width / 2;
            centerY = height / 2;
        }

        @Override
        protected void applyTransformation(float interpolatedTime, Transformation t) {
            super.applyTransformation(interpolatedTime, t);

            if (interpolatedTime < 0.25f) {
                // 1-1.1
                float ss = interpolatedTime * 0.4f + 1f;
                Matrix matrix = t.getMatrix();
                matrix.setScale(ss, ss, centerX, centerY);
            } else if (interpolatedTime >= 0.25f && interpolatedTime < 0.5f) {
                // 1.1-1
                float ss = (0.5f - interpolatedTime) * 0.4f + 1f;
                Matrix matrix = t.getMatrix();
                matrix.setScale(ss, ss, centerX, centerY);
            } else if (interpolatedTime >= 0.5f && interpolatedTime < 0.75f) {
                // 1-0.9
                float ss = (0.75f - interpolatedTime) * 0.4f + 0.9f;
                Matrix matrix = t.getMatrix();
                matrix.setScale(ss, ss, centerX, centerY);
            } else if (interpolatedTime >= 0.75f && interpolatedTime <= 1f) {
                // 0.9-1
                float ss = interpolatedTime * 0.4f + 0.6f;
                Matrix matrix = t.getMatrix();
                matrix.setScale(ss, ss, centerX, centerY);
            }
        }
    }

    /**
     * 进度条动画
     */
    public class BarAnimation extends Animation {


        public BarAnimation() {
        }

        /**
         * 然后调用postInvalidate()不停的绘制view。
         */
        @Override
        protected void applyTransformation(float interpolatedTime,
                                           Transformation t) {

            super.applyTransformation(interpolatedTime, t);
            if (mNewAngle - mOldAngle >= 0) {
                // 正向
                mSweepAngle = interpolatedTime * (mNewAngle - mOldAngle);
            } else {
                // 逆向
                mSweepAngle = interpolatedTime * (mNewAngle - mOldAngle);
            }
            postInvalidate();
        }
    }

    @Override
    public void onAnimationStart(Animation animation) {
        isAnimation = true;
    }

    @Override
    public void onAnimationEnd(Animation animation) {
        isAnimation = false;

    }

    @Override
    public void onAnimationRepeat(Animation animation) {
        // TODO Auto-generated method stub

    }

    private int dp2px(Context context, float dpVal) {
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
                dpVal, context.getResources().getDisplayMetrics());
    }

}

这是attrs.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="PickerView">

        <attr name="isLoop" format="boolean" />

    </declare-styleable>

    <declare-styleable name="RoundView">
        <!--圆环半径-->
        <attr name="radius" format="dimension"/>
        <!--圆环宽度-->
        <attr name="ring_width" format="dimension"/>
        <!--圆环颜色-->
        <attr name="ring_color" format="color"/>
        <!--进度圆环宽度-->
        <attr name="progress_ring_width" format="dimension"/>
        <!--进度圆环开始颜色-->
        <attr name="progress_ring_start_color" format="color"/>
        <!--进度圆环结束颜色-->
        <attr name="progress_ring_end_color" format="color"/>
        <attr name="text_color" format="color" />
        <attr name="text_size" format="integer" />
        <attr name="android_radius" format="integer" />

    </declare-styleable>
</resources>

这是使用方法

    <com.basic.security.widget.RoundView
        android:id="@+id/round_view"
        android:layout_width="@dimen/h216"
        android:layout_height="@dimen/h216"
        android:layout_centerInParent="true"
        android:layout_gravity="center_horizontal"
        android:layout_marginTop="@dimen/h53" />
    <!-- RoundView最大值为360,暂不支持修改-->
round_view.setAngle(350);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值