自定义控件实现——环形饼图

来源:互联网 发布:matlab dsp编程 编辑:程序博客网 时间:2024/06/06 16:51

这里写图片描述

1 需求:

1) 根据不同份额占用等比例的份额,用不同颜色表示

2) 饼图要求:环形;有阴影效果;不同份额颜色不同;从外到内颜色不同

3) 加载数据有动画效果

2 原理

1)封装Bean:表示的值,开始颜色,结束颜色;

2)drawArc +paint宽度设置为圆环宽度;

3)颜色渐变:

RadialGradient gradient = new RadialGradient(centerX, centerY, radius,
new int[]{Color.TRANSPARENT, Color.TRANSPARENT, arcs.get(i).startColor, arcs.get(i).endColor},
new float[]{0, innerRadius / outerRadius, innerRadius / outerRadius, 1},
Shader.TileMode.CLAMP);
paint.setShader(gradient);//RadialGradient

3)阴影效果:

Paint.setShadowLayer(shadowRadius / 2, 0, shadowRadius / 4, 0xFFDF4242);

4)动画效果:

记录一个开始时间startTime,动画要执行时间为固定 值;
System.currentTimeMillis() 不断和startTime比较,到达固定值,结束动画
进度:时间比例计算
实现:onDraw中判断时间未到的话直接invalidate();

3 代码实现

**package com.bpj.piechart;import android.content.Context;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.graphics.RadialGradient;import android.graphics.RectF;import android.graphics.Shader;import android.util.AttributeSet;import android.util.Log;import android.view.View;import java.util.ArrayList;import java.util.List;/** * 作者 chenli * 日期 2017/8/24 * 描述 饼图 **/public class PieChartView extends View {    private static float ANGLE_ROUND = 360f;    private static float ANGLE_START = -90f;    private static int TIME_ANIM = 800;    // 可封装为attrs    private float outerRadius;    private float innerRadius;    private float shadowRadius;    private int count;    private float[] startAngles;    private float[] sweepAngles;    private ArcRing[] arcRings;    private RectF rect; // 圆环内外环1/2处的圆所在区域    private float radius; // 圆环内外环1/2处的半径    private float width; // 圆环内外环之间的宽度    private float centerX; // 圆环圆心x    private float centerY; // 圆环圆心y    private Paint paint;    private long timeStart;    private boolean set;    public PieChartView(Context context) {        super(context);        init();    }    public PieChartView(Context context, AttributeSet attrs) {        super(context, attrs);        init();    }    public PieChartView(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        init();    }    private void init() {        setLayerType(View.LAYER_TYPE_SOFTWARE, null);        outerRadius =  dip2px(getContext(), 55); // 55dp        innerRadius =  dip2px(getContext(), 32); // 32dp        shadowRadius =  dip2px(getContext(), 10); // 10dp        width = outerRadius - innerRadius;        radius = outerRadius - width / 2;        centerX = outerRadius + shadowRadius;        centerY = outerRadius + shadowRadius;        rect = new RectF(centerX - radius, centerY - radius, centerX + radius, centerY + radius);        // init paint        paint = new Paint();        paint.setColor(0xFFDF4242);        paint.setShadowLayer(shadowRadius / 2, 0, shadowRadius / 4, 0xFFDF4242);        paint.setStrokeWidth(width - 1);        paint.setStyle(Paint.Style.STROKE);    }    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        int widthMode = MeasureSpec.getMode(widthMeasureSpec);        int widthSize = MeasureSpec.getSize(widthMeasureSpec);        int heightMode = MeasureSpec.getMode(heightMeasureSpec);        int heightSize = MeasureSpec.getSize(heightMeasureSpec);        int width;        int height;        if (widthMode == MeasureSpec.EXACTLY) {            width = widthSize;        } else {            width = (int) (getPaddingLeft() + outerRadius * 2 + shadowRadius * 2 + getPaddingRight());        }        if (heightMode == MeasureSpec.EXACTLY) {            height = heightSize;        } else {            height = (int) (getPaddingTop() + outerRadius * 2 + shadowRadius * 2 + getPaddingBottom());        }        setMeasuredDimension(width, height);    }    @Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        if (count == 0) {            return;        }        long timeCurrent = System.currentTimeMillis();        if (timeCurrent - this.timeStart < TIME_ANIM) {            float angle = (timeCurrent - this.timeStart) * ANGLE_ROUND / TIME_ANIM;            canvas.drawArc(rect, ANGLE_START, angle, false, paint);            for (int i = 0; i < count; i++) {                arcRings[i].draw(canvas, angle);            }            invalidate();        } else {            canvas.drawArc(rect, ANGLE_START, ANGLE_ROUND, false, paint);            for (int i = 0; i < count; i++) {                arcRings[i].draw(canvas);            }        }    }    private static class ArcRing {        Paint paint;        RectF rect;        float startAngle;        float sweepAngle;        ArcRing(float width, Shader gradient, RectF rect, float startAngle, float sweepAngle) {            this.rect = rect;            this.startAngle = startAngle;            this.sweepAngle = sweepAngle;            paint = new Paint();            paint.setAntiAlias(true);            paint.setShader(gradient);            paint.setStrokeWidth(width);            paint.setStyle(Paint.Style.STROKE);        }        void draw(Canvas canvas) {            canvas.drawArc(rect, startAngle, sweepAngle, false, paint);        }        void draw(Canvas canvas, float angle) {            if (angle >= startAngle - ANGLE_START) {                if (angle <= startAngle - ANGLE_START + sweepAngle) {                    canvas.drawArc(rect, startAngle, angle + ANGLE_START - startAngle, false, paint);                } else {                    canvas.drawArc(rect, startAngle, sweepAngle, false, paint);                }            }        }    }    public void update(List<Arc> arcs) {        if (arcs == null || arcs.isEmpty()) {            clear();            return;        }        this.timeStart = System.currentTimeMillis();        count = arcs.size();        startAngles = new float[count];        sweepAngles = new float[count];        arcRings = new ArcRing[count];        float totalProperties = 0f;        for (Arc arc : arcs) {            totalProperties += Math.abs(arc.value);        }        float usedSweepAngle = 0;        for (int i = 0; i < count; i++) {            if (i == count - 1) {                sweepAngles[i] = ANGLE_ROUND - usedSweepAngle;            } else {                if (totalProperties < 0.01) {                    sweepAngles[i] = ANGLE_ROUND / count;                } else {                    sweepAngles[i] = Math.abs(arcs.get(i).value) * ANGLE_ROUND / totalProperties;                }            }            if (i == 0) {                startAngles[i] = ANGLE_START;            } else {                startAngles[i] = startAngles[i - 1] + sweepAngles[i - 1];            }            RadialGradient gradient = new RadialGradient(centerX, centerY, radius,                    new int[]{Color.TRANSPARENT, Color.TRANSPARENT, arcs.get(i).startColor, arcs.get(i).endColor},                    new float[]{0, innerRadius / outerRadius, innerRadius / outerRadius, 1},                    Shader.TileMode.CLAMP);            arcRings[i] = new ArcRing(width, gradient, rect, startAngles[i], sweepAngles[i]);            usedSweepAngle += sweepAngles[i];        }        invalidate();    }    public void clear() {        count = 0;        startAngles = null;        sweepAngles = null;        arcRings = null;        invalidate();    }    public List<Float> getPercentages() {        List<Float> floats = new ArrayList<>();        if (sweepAngles != null) {            for (int i = 0; i < sweepAngles.length; i++) {                floats.add(sweepAngles[i] / ANGLE_ROUND);            }        }        return floats;    }    public static class Arc {        float value;        int startColor;        int endColor;        public Arc(float value, int startColor, int endColor) {            this.value = value;            this.startColor = startColor;            this.endColor = endColor;        }    }    public static int dip2px(Context context, float dpValue) {        final float scale = context.getResources().getDisplayMetrics().density;        return (int) (dpValue * scale + 0.5f);    }}**

调用:

PieChartView.Arc arc1 = new PieChartView.Arc(10,0xFFFA5539,0xFFFA3252);        PieChartView.Arc arc2 = new PieChartView.Arc(20,0xFFFCCB3C,0xFFF78E26);        PieChartView.Arc arc3 = new PieChartView.Arc(30,0xFF8969FF,0xFF157EFB);        PieChartView.Arc arc4 = new PieChartView.Arc(40,0xFF17EAD9,0xFF60B3EA);        PieChartView.Arc arc5 = new PieChartView.Arc(40,0xFFDAAB66,0xFFB18545);        List<PieChartView.Arc> list = new ArrayList<>();        list.add(arc1);        list.add(arc2);        list.add(arc3);        list.add(arc4);        list.add(arc5);        pcv.update(list);
阅读全文
'); })();
0 0
原创粉丝点击
热门IT博客
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 罪恶都市秘籍大全 侠盗飞车秘籍大全 维多利亚2秘籍 帝国时代3秘籍 侠盗猎车手秘籍大全 魔兽秘籍大全 血战上海滩秘籍 维多利亚秘籍 圣安地列斯秘籍大全 男神恋爱秘籍 三国群英传2秘籍 魔兽争霸秘籍大全 魔兽无敌秘籍 侠盗猎车手3秘籍 安地列斯秘籍 侠盗猎车手4秘籍 侠盗飞车3秘籍 侠盗猎车手2秘籍 狭盗飞车的秘籍 秘籍圣安地列斯 侠盗猎车的秘籍全部 侠盗猎车3秘籍飞机 秘诀的意思 秘诀 密级 侠盗罪恶都市秘籍 快穿男神恋爱秘籍 lostlife过关秘籍 三国全面战争秘籍 侠盗猎车飞机秘籍 侠盗猎车手罪恶都市秘籍 快穿之男神恋爱秘籍 侠盗猎车罪恶都市秘籍 三国群英传7完整秘籍编码 侠盗飞车圣安地列斯秘籍 秘葬天书 秘葬天书全文免费 山海秘藏 秘藏 异宝秘藏 地下秘藏