带动效的环形进度图

    xiaoxiao2021-03-26  31

    效果图(完整代码在文章末尾贴出)

    图表分析

    确定控件width、height,Math.min(width, height)获取当中的最小值,设定为圆形的直径(也可减去一个数值作为预留的边距,但要注意在以后的绘图中计算进去)

    绘制背景色圆形:canvas.drawCircle(float centerX, float centerY, float radius, Paint paint); 参数说明:(圆心坐标点x, 圆心坐标点y, 圆形半径, 画笔)

    绘制进度弧线:canvas.drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter, Paint paint); 具体使用说明移步http://www.cnblogs.com/tjudzj/p/4387145.html

    绘制前景色圆形:前景色圆形半径 = 背景色半径 - 进度条的宽度

    代码说明

    创建java文件继承自View, 并实现构造方法

    public class CircleRingGraph extends View { public CircleRingGraph(Context context, AttributeSet attrs) { super(context, attrs); initDefineAttr(context, attrs); initPaint(); } public CircleRingGraph(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initDefineAttr(context, attrs); initPaint(); } }

    initDefineAttr(context, attrs);

    该方法内部获取xml文件里的自定义的属性信息

    如何添加自定义的属性信息:

    在values文件夹下创建attrs.xml文件声明自定义属性信息的名称、数值类型(name、format),如下: <!-- 圆形进度条类型图表的相关属性 --> <declare-styleable name="CircleRingGraph"> <!-- 进度条的背景色 --> <attr name="progressBackgroundColor" format="color" /> <!-- 进度条颜色 --> <attr name="progressColor" format="color" /> <!-- 中心圆形的颜色 --> <attr name="circleHeartColor" format="color" /> <!-- 进度条的宽度 --> <attr name="progressWidth" format="dimension" /> <!-- 进度条是否显示圆形头部 --> <attr name="progressRoundCap" format="boolean" /> <!-- 圆心显示的文字 --> <attr name="centerText" format="string" /> <!-- 圆心显示的文字颜色 --> <attr name="centerTextColor" format="color" /> <!-- 圆心显示的文字大小 --> <attr name="centerTextSize" format="dimension" /> </declare-styleable> 在自定义View里边获取并设置xml文件里的自定义属性信息,即initDefineAttr(context, attrs) 方法里的内容 private void initDefineAttr(Context context, AttributeSet attrs) { if (attrs == null) return; DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics(); TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CircleRingGraph); int count = typedArray.getIndexCount(); for (int i = 0; i < count; i++) { int attr = typedArray.getIndex(i); switch (attr) { case R.styleable.CircleRingGraph_progressBackgroundColor: colorOut = typedArray.getColor(attr, context.getResources().getColor(R.color.circle_out_blue)); break; case R.styleable.CircleRingGraph_progressColor: colorPro = typedArray.getColor(attr, context.getResources().getColor(R.color.circle_progress_blue)); break; case R.styleable.CircleRingGraph_circleHeartColor: colorIn = typedArray.getColor(attr, context.getResources().getColor(R.color.circle_in)); break; case R.styleable.CircleRingGraph_progressRoundCap: roundCap = typedArray.getBoolean(attr, Boolean.FALSE); break; case R.styleable.CircleRingGraph_progressWidth: strokeWidth = typedArray.getDimension(attr, DEFAULT_STROKE_WIDTH); break; case R.styleable.CircleRingGraph_centerText: centerText = typedArray.getString(attr); break; case R.styleable.CircleRingGraph_centerTextColor: centerTextColor = typedArray.getColor(attr, context.getResources().getColor(R.color.colorBlack)); break; case R.styleable.CircleRingGraph_centerTextSize: centerTextSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, typedArray.getDimensionPixelSize(attr, 16), displayMetrics); break; default: break; } } typedArray.recycle(); }

    initPaint() 用来设置背景圆、进度条、前景圆、文本数值的Paint的基本信息,放在initDefineAttr() 之后是因为要将自定义的一些属性值设置给Paint。

    private void initPaint() { paintOut = new Paint(); paintOut.setAntiAlias(true); paintOut.setStyle(Paint.Style.FILL); paintOut.setColor(colorOut); paintIn = new Paint(); paintIn.setAntiAlias(true); paintIn.setStyle(Paint.Style.FILL); paintIn.setColor(colorIn); paintPro = new Paint(); paintPro.setAntiAlias(true); if (roundCap) paintPro.setStrokeCap(Paint.Cap.ROUND); paintPro.setStyle(Paint.Style.STROKE); paintPro.setStrokeWidth(strokeWidth); paintPro.setColor(colorPro); paintTxt = new Paint(); paintTxt.setAntiAlias(true); paintTxt.setTextSize(centerTextSize); paintTxt.setTextAlign(Paint.Align.CENTER); paintTxt.setColor(centerTextColor); }

    onSizeChanged()内主要是获取并设置控件的基本数值信息

    @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { radiusOut = Math.min(w, h) / 2 - DEFAULT_PADDING; radiusIn = radiusOut - strokeWidth; centerX = w / 2; centerY = h / 2; float left = centerX - radiusOut + strokeWidth / 2; float top = centerY - radiusOut + strokeWidth / 2; float right = left + radiusOut * 2 - strokeWidth; float bottom = top + radiusOut * 2 - strokeWidth; rectF = new RectF(left, top, right, bottom); textBaseLineX = centerX; textBaseLineY = centerY + centerTextSize / 3; super.onSizeChanged(w, h, oldw, oldh); }

    onSizeChanged() 当中用到的一些变量的解释

    radiusOut :背景色圆形的半径

    DEFAULT_PADDING:默认预留的控件的Padding

    radiusIn :前景色圆形的半径

    centerX :控件的中心坐标点 x

    centerY:控件的中心坐标点 y

    strokeWidth:进度条的宽度

    rectF :弧形进度条所占的正方形区域

    textBaseLineX :中心数值的基线坐标点 x

    textBaseLineY :中心数值的基线坐标点 y

    当所有的信息都齐活之后,接下来就是绘制了,绘制当然是用onDraw() 方法了, 废话少说,看代码

    @Override protected void onDraw(Canvas canvas) { drawCircleRing(canvas); super.onDraw(canvas); } /** * draw circle ring */ private void drawCircleRing(Canvas canvas) { // 画灰色的圆 canvas.drawCircle(centerX, centerY, radiusOut, paintOut); // 画进度环 if (progress != 0f) { canvas.drawArc(rectF, -90, progress, false, paintPro); } // 画内填充圆 canvas.drawCircle(centerX, centerY, radiusIn, paintIn); //画中心位置文字 canvas.drawText((int) progress + "", textBaseLineX, textBaseLineY, paintTxt); }

    看起来soEasy对不对?对的,就是这么简单,不过要注意一点canvas.drawArc()的时候,因为我默认设置的是progress = 0;所以加上if(progress != 0f)的判断,不然界面一进来就默认绘制一段进度条

    现在问题来了,既然是带动效的,那一定要能够动起来的。好,那就来加点特效,加动画!

    public void doAnimation() { ValueAnimator animator = ValueAnimator.ofObject(new ProgressEvaluator(), 0f, progress); animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { progress = (float) animation.getAnimatedValue(); invalidate(); } }); animator.setDuration(1000); animator.setInterpolator(new OvershootInterpolator()); animator.start(); } private class ProgressEvaluator implements TypeEvaluator<Float> { @Override public Float evaluate(float fraction, Float startValue, Float endValue) { return startValue + fraction * (endValue - startValue); } }

    看代码页依然没什么难的,重点有三:

    1、 ProgressEvaluator() 的实现,主要在于startValue -> endValue 的关系公式的实现

    2、 onAnimationUpdate(ValueAnimator animation) 方法内记得调用invalidate() 来刷新界面,不然怎么会动呢?

    3、 动效设置 animator.setInterpolator(new OvershootInterpolator()) Android默认提供了集中动效插值器,各位可以自己尝试下效果。

    有关动画的详细的知识,请移步: http://blog.csdn.net/harvic880925/article/details/50995268

    本篇完整代码

    package customview; import android.animation.TypeEvaluator; import android.animation.ValueAnimator; import android.content.Context; import android.content.res.TypedArray; import android.graphics.BlurMaskFilter; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.LinearGradient; import android.graphics.Paint; import android.graphics.RectF; import android.graphics.Shader; import android.graphics.SweepGradient; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.util.TypedValue; import android.view.View; import android.view.animation.OvershootInterpolator; import com.example.zpf.animmenu.R; /** * Created by zpf on 2016/11/7. */ public class CircleRingGraph extends View { /** * 默认的Padding */ private final float DEFAULT_PADDING = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 16, getResources().getDisplayMetrics()); /** 默认的进度条的宽度 */ private final float DEFAULT_STROKE_WIDTH = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 16, getResources().getDisplayMetrics()); /** * centerX:中心坐标点x * centerY:中心坐标点y * radiusOut:背景色圆形的半径 * radiusIn:前景色圆形的半径 * */ private float centerX, centerY, radiusOut, radiusIn; /** * paintOut:背景色圆形画笔 * paintIn:前景色圆形画笔 * paintPro:进度条的画笔 * paintTxt:中心数据值文本的画笔 * */ private Paint paintOut, paintIn, paintPro, paintTxt; /** * colorOut: 进度条背景色 * colorIn: 圆心背景色 * colorPro: 进度条的颜色 */ private int colorOut = getResources().getColor(R.color.colorGray), colorIn = getResources().getColor(R.color.circle_in), colorPro = getResources().getColor(R.color.circle_progress_blue); /** * 用来画圆弧的RectF */ private RectF rectF; /** * 进度条的宽度 */ private float strokeWidth = DEFAULT_STROKE_WIDTH; /** * 显示圆形进度条的头部 */ private boolean roundCap = Boolean.FALSE; /** * 进度条显示的进度 */ private float progress = 0; /** * 圆心位置显示的Text * centerText: 圆心位置的文本信息 * colorCenterText: TextView文字颜色 * centerTextSize: TextView文字大小 */ private String centerText; private int centerTextColor = getResources().getColor(R.color.colorBlack); private float centerTextSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 16, getResources().getDisplayMetrics()); /** * textBaseLineX:绘制文本的基线x坐标点 * textBaseLineY:绘制文本的基线y坐标点 * */ private float textBaseLineX, textBaseLineY; public CircleRingGraph(Context context) { super(context); } public CircleRingGraph(Context context, AttributeSet attrs) { super(context, attrs); initDefineAttr(context, attrs); } public CircleRingGraph(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initDefineAttr(context, attrs); } public float getProgress() { return progress; } public void setProgress(float progress) { this.progress = progress; doAnimation(); } /** * 获取自定义的属性值 */ private void initDefineAttr(Context context, AttributeSet attrs) { if (attrs == null) return; DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics(); TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CircleRingGraph); int count = typedArray.getIndexCount(); for (int i = 0; i < count; i++) { int attr = typedArray.getIndex(i); switch (attr) { case R.styleable.CircleRingGraph_progressBackgroundColor: colorOut = typedArray.getColor(attr, context.getResources().getColor(R.color.circle_out_blue)); break; case R.styleable.CircleRingGraph_progressColor: colorPro = typedArray.getColor(attr, context.getResources().getColor(R.color.circle_progress_blue)); break; case R.styleable.CircleRingGraph_circleHeartColor: colorIn = typedArray.getColor(attr, context.getResources().getColor(R.color.circle_in)); break; case R.styleable.CircleRingGraph_progressRoundCap: roundCap = typedArray.getBoolean(attr, Boolean.FALSE); break; case R.styleable.CircleRingGraph_progressWidth: strokeWidth = typedArray.getDimension(attr, DEFAULT_STROKE_WIDTH); break; case R.styleable.CircleRingGraph_centerText: centerText = typedArray.getString(attr); break; case R.styleable.CircleRingGraph_centerTextColor: centerTextColor = typedArray.getColor(attr, context.getResources().getColor(R.color.colorBlack)); break; case R.styleable.CircleRingGraph_centerTextSize: centerTextSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, typedArray.getDimensionPixelSize(attr, 16), displayMetrics); break; default: break; } } typedArray.recycle(); initPaint(); } /** * init Paint */ private void initPaint() { paintOut = new Paint(); paintOut.setAntiAlias(true); paintOut.setStyle(Paint.Style.FILL); paintOut.setColor(colorOut); paintIn = new Paint(); paintIn.setAntiAlias(true); paintIn.setStyle(Paint.Style.FILL); paintIn.setColor(colorIn); paintPro = new Paint(); paintPro.setAntiAlias(true); if (roundCap) paintPro.setStrokeCap(Paint.Cap.ROUND); paintPro.setStyle(Paint.Style.STROKE); paintPro.setStrokeWidth(strokeWidth); paintPro.setColor(colorPro); // setLayerType(LAYER_TYPE_SOFTWARE, null); //setMaskFilter // paintPro.setMaskFilter(new BlurMaskFilter(1, BlurMaskFilter.Blur.INNER)); //set shadow // paintPro.setShadowLayer(40, 0, 0, getResources().getColor(R.color.black_alpha_3)); //雷达渐变 // Shader shaderPro = new SweepGradient(centerX, centerY, // getResources().getColor(R.color.colorPink), getResources().getColor(R.color.colorGreen)); // paintPro.setShader(shaderPro); //线性渐变 // Shader shaderLinear = new LinearGradient(0, 0, 200, 0, Color.WHITE, Color.RED, // Shader.TileMode.CLAMP); // paintPro.setShader(shaderLinear); paintTxt = new Paint(); paintTxt.setAntiAlias(true); paintTxt.setTextSize(centerTextSize); paintTxt.setTextAlign(Paint.Align.CENTER); paintTxt.setColor(centerTextColor); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { radiusOut = Math.min(w, h) / 2 - DEFAULT_PADDING; radiusIn = radiusOut - strokeWidth; centerX = w / 2; centerY = h / 2; float left = centerX - radiusOut + strokeWidth / 2; float top = centerY - radiusOut + strokeWidth / 2; float right = left + radiusOut * 2 - strokeWidth; float bottom = top + radiusOut * 2 - strokeWidth; rectF = new RectF(left, top, right, bottom); textBaseLineX = centerX; textBaseLineY = centerY + centerTextSize / 3; super.onSizeChanged(w, h, oldw, oldh); } @Override protected void onDraw(Canvas canvas) { drawCircleRing(canvas); super.onDraw(canvas); } /** * draw circle ring */ private void drawCircleRing(Canvas canvas) { // 画灰色的圆 canvas.drawCircle(centerX, centerY, radiusOut, paintOut); // 画进度环 if (progress != 0f) { canvas.drawArc(rectF, -90, progress, false, paintPro); } // 画内填充圆 canvas.drawCircle(centerX, centerY, radiusIn, paintIn); //画中心位置文字 canvas.drawText((int) progress + "", textBaseLineX, textBaseLineY, paintTxt); } public void doAnimation() { ValueAnimator animator = ValueAnimator.ofObject(new ProgressEvaluator(), 0f, progress); animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { progress = (float) animation.getAnimatedValue(); invalidate(); } }); animator.setDuration(1000); animator.setInterpolator(new OvershootInterpolator()); animator.start(); } private class ProgressEvaluator implements TypeEvaluator<Float> { @Override public Float evaluate(float fraction, Float startValue, Float endValue) { return startValue + fraction * (endValue - startValue); } } }

    自定义的额属性相关的标签内容如下:

    <!-- 圆形进度条类型图表的相关属性 --> <declare-styleable name="CircleRingGraph"> <!-- 进度条的背景色 --> <attr name="progressBackgroundColor" format="color" /> <!-- 进度条颜色 --> <attr name="progressColor" format="color" /> <!-- 中心圆形的颜色 --> <attr name="circleHeartColor" format="color" /> <!-- 进度条的宽度 --> <attr name="progressWidth" format="dimension" /> <!-- 进度条是否显示圆形头部 --> <attr name="progressRoundCap" format="boolean" /> <!-- 圆心显示的文字 --> <attr name="centerText" format="string" /> <!-- 圆心显示的文字颜色 --> <attr name="centerTextColor" format="color" /> <!-- 圆心显示的文字大小 --> <attr name="centerTextSize" format="dimension" /> </declare-styleable>

    如有问题,欢迎留言评论!

    转载请注明原文地址: https://ju.6miu.com/read-658524.html

    最新回复(0)