首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Android-可旋转、平移的饼状图(PieChartView)

Android-可旋转、平移的饼状图(PieChartView)

作者头像
code_horse
发布2018-07-02 15:09:10
1.5K0
发布2018-07-02 15:09:10
举报
文章被收录于专栏:Android NoteAndroid Note
前言

这次的饼图和之前写过的都不太一样。主要是饼图的旋转是通过Button去触发,被选中的某块需要平移出来。

好了,先看一下效果图

旋转的卡顿是模拟机的原因,真机是没问题的♪(∇*)

自定义View

public class AnimatePieChartView extends View {

    public static final String TAG = "ez";
    //默认起始的旋转角度
    private final float DEFAULT_START_ANGLE = 180;
    //某块饼图平移的距离
    public static final int TRANS_DIS = -20;
    private Paint mPaintOuter;
    private Paint mPaintCenter;
    private Paint mPaintShadow;

    private int mPaddingTop;
    private int mPaddingBottom;
    private int mPaddingStart;
    private int mPaddingEnd;

    //圆心
    private int mCenterX;
    private int mCenterY;

    //开始角度
    private float mStartAngle;
    private float mMaxValue;
    //文字大小
    private float mTextSize;
    //阴影大小
    private float mShaderSize;
    //当前颜色
    private int mCurrentColor;
    //当前选中的index
    private int mIndex;
    //颜色
    private List<Integer> mPieColorList;
    //颜色占比
    private List<Float> mPieValueList;
    //饼图文字
    private List<String> mPieStringList;
    //选中角度
    private List<Float> angleList;
    //半径
    private int mRadius;
    //中心圆半径
    private int circleRadius;
    //中心圆文字
    private String text;
    //中心圆颜色
    private int centerColor;

    public AnimatePieChartView(Context context) {
        super(context, null);
    }

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

    public AnimatePieChartView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        //自定义一些属性
        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.PieChartView);

        mRadius = a.getDimensionPixelSize(R.styleable.PieChartView_pie_radius,
                getResources().getDimensionPixelSize(R.dimen.pie_default_radius));
        circleRadius = a.getDimensionPixelSize(R.styleable.PieChartView_centerCircle_radius,
                getResources().getDimensionPixelSize(R.dimen.pie_center_radius));
        mTextSize = a.getDimension(R.styleable.PieChartView_textSize,
                getResources().getDimension(R.dimen.pie_text_size));
        mShaderSize = a.getDimension(R.styleable.PieChartView_shaderSize,
                getResources().getDimension(R.dimen.pie_shader_size));

        centerColor = getResources().getColor(R.color.color_window_background);

        a.recycle();

        mPaddingTop = getPaddingTop();
        mPaddingBottom = getPaddingBottom();
        mPaddingStart = getPaddingLeft();
        mPaddingEnd = getPaddingRight();

        initPaint();
    }

    /**
     * 初始化Paint
     */
    private void initPaint() {
        mPieColorList = new ArrayList<>();
        mPieValueList = new ArrayList<>();
        mPieStringList = new ArrayList<>();
        angleList = new ArrayList<>();


        mPaintOuter = new Paint();
        mPaintOuter.setStyle(Paint.Style.FILL);
        mPaintOuter.setAntiAlias(true);

        mPaintCenter = new Paint();
        mPaintCenter.setColor(centerColor);
        mPaintCenter.setStyle(Paint.Style.FILL);
        mPaintCenter.setAntiAlias(true);
        mPaintCenter.setTextSize(mTextSize);
        mPaintCenter.setTextAlign(Paint.Align.CENTER);

        mPaintShadow = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaintShadow.setAntiAlias(true);
    }

    /**
     * 获取饼图每一部分的旋转角度
     */
    private float getRotationAngle(int i) {
        float angleR;
        float angleT = angleList.get(i);
        if (angleT <= 270f && angleT >= 90f) {
            angleR = 90f - angleT;
        } else if (angleT > 270f && angleT <= 360f) {
            angleR = 360f - angleT + 90f;
        } else if (angleT >= 0 && angleT < 90) {
            angleR = 90 - angleT;
        } else {
            angleR = 0;
        }

        for (int id = 0; id < angleList.size(); id++) {
            float temp = angleList.get(id) + angleR;
            if (temp > 360f) {
                temp -= 360f;
            } else if (temp < 0) {
                temp += 360f;
            }
            angleList.set(id, temp);
        }
        return angleR;
    }

    //测量View的宽高
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);

        int mWidth = mRadius * 2 + mPaddingStart + mPaddingEnd;
        int mHeight = mRadius * 2 + mPaddingTop + mPaddingBottom;

        if (getLayoutParams().width == ViewGroup.LayoutParams.WRAP_CONTENT &&
                getLayoutParams().height == ViewGroup.LayoutParams.WRAP_CONTENT) {
            setMeasuredDimension(mWidth, mHeight);
        } else if (getLayoutParams().width == ViewGroup.LayoutParams.WRAP_CONTENT) {
            setMeasuredDimension(mWidth, heightSize);
        } else if (getLayoutParams().height == ViewGroup.LayoutParams.WRAP_CONTENT) {
            setMeasuredDimension(widthSize, mHeight);
        }
    }
    
    //size改变后,重新测量View
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mCenterX = mPaddingStart + (w - mPaddingStart - mPaddingEnd) / 2;
        mCenterY = mPaddingTop + (h - mPaddingTop - mPaddingBottom) / 2;
        mPaintShadow.setShader(new RadialGradient(mCenterX, mCenterY,
                circleRadius + mShaderSize,
                Color.TRANSPARENT, Color.TRANSPARENT, Shader.TileMode.CLAMP));
    }

    /**
     * 旋转前的饼图
     */
    private void drawPie(Canvas canvas, float amount,int i) {
        mPaintOuter.setColor(mCurrentColor);
        float mAngle = 360  * amount / mMaxValue;
        RectF oval = new RectF(mCenterX - mRadius, mCenterY - mRadius,mCenterX + mRadius,mCenterY + mRadius);
        canvas.drawArc(oval, mStartAngle, mAngle, true, mPaintOuter);
        mStartAngle += mAngle;
    }

    /**
     * 旋转后的饼图
     */
    private void drawPieTouch(Canvas canvas, float amount,int i) {
        mPaintOuter.setColor(mCurrentColor);
        float mAngle = 360  * amount / mMaxValue;
        float mRadiusTemp = mRadius ;
        RectF oval = new RectF(mCenterX - mRadiusTemp, mCenterY - mRadiusTemp,mCenterX + mRadiusTemp,mCenterY + mRadiusTemp);
        canvas.drawArc(oval, mStartAngle + mAngle , mAngle - mAngle  * 2, true, mPaintOuter);
        mStartAngle += mAngle;
        canvas.drawText(mPieStringList.get(i),getMeasuredWidth()/2,getMeasuredHeight()/4,mPaintCenter);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        for (int i = 0; i < mPieValueList.size(); i++) {
            mCurrentColor = mPieColorList.get(i);
            if (i == mIndex) {
                canvas.save();
                canvas.translate(0,TRANS_DIS);
                drawPieTouch(canvas, mPieValueList.get(i),i);
                canvas.restore();
            } else {
                drawPie(canvas, mPieValueList.get(i),i);
            }
        }
        canvas.drawCircle(mCenterX, mCenterY,
                circleRadius + mShaderSize, mPaintShadow);
        mPaintCenter.setColor(centerColor);
    }

    public void setCenterText(String text){
        this.text=text;
    }

    /**
     *
     * 旋转选中的某一项
     */
    public void onAnimatedPie(int i) {
        mIndex = i;
        float angle = getRotationAngle(i);
        ValueAnimator animatorRotation;
        animatorRotation = ValueAnimator.ofFloat(mStartAngle, mStartAngle + angle);
        animatorRotation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                mStartAngle = (Float) animation.getAnimatedValue();
                invalidate();
            }
        });

        int time = (int) (1000 * Math.abs(angle) / 360);

        animatorRotation.setDuration(time);
        animatorRotation.start();
    }

    /**
     * 饼图的各个属性
     *
     */
    public void setPie(List<PieData> pieList) {
        mMaxValue = 0;
        mPieColorList = new ArrayList<>();
        mPieStringList = new ArrayList<>();
        mPieValueList = new ArrayList<>();
        angleList = new ArrayList<>();

        for (PieData pie : pieList) {
            mPieColorList.add(pie.pieColor);
            mPieValueList.add(pie.pieValue);
            mMaxValue += pie.pieValue;
            mPieStringList.add(pie.pieString);
        }

        float angleTemp;
        float startAngleTemp = DEFAULT_START_ANGLE;

        for (float v : mPieValueList) {
            angleTemp = 360 * v / mMaxValue;

            angleList.add(startAngleTemp + angleTemp / 2);

            startAngleTemp += angleTemp;
        }
    }

}

调用方式

    //每个饼图的占比
    private float[] mPies;
    //饼图
    private AnimatePieChartView mAnimatePieChartView;
    //初始化当前的index
    private int mIndex=0;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_animate_pie_view_layout);
        findView();
        mAnimatePieChartView = (AnimatePieChartView) findViewById(R.id.id_animate_pie_view);
        setPieData(mAnimatePieChartView);
    }
    //findViewById
    private void findView(){
        Button btnPre= (Button) findViewById(R.id.id_btn_pre);
        Button btnNext= (Button) findViewById(R.id.id_btn_next);

        btnPre.setOnClickListener(this);
        btnNext.setOnClickListener(this);
    }
    //初始化饼图属性
    private void setPieData(AnimatePieChartView animatePieChartView) {
        final TypedArray typedArray = getResources().obtainTypedArray(R.array.ring_colors);
        final int size = 5;
        final int length = typedArray.length();
        //饼图数据集合
        List<PieData> pieEntryList = new ArrayList<>();
        mPies = new float[]{20f, 30f, 10f, 50f, 15f};
        String[] positions=new String[]{"上单","打野","中单","下路","辅助"};
        int color ;
        for(int i = 0; i < size; i++) {
            //饼图每块的颜色
            if(i >= length) {
                color = typedArray.getColor(length - 1, 0);
            } else {
                color = typedArray.getColor(i, 0);
            }
            //每块饼图所需要的数据
            PieData pe = new PieData(mPies[i],positions[i] , color);
            
            pieEntryList.add(pe);
        }
        animatePieChartView.setPie(pieEntryList);
        if(size > 1) {
            animatePieChartView.onTouchPie(0);
        } else {
            animatePieChartView.invalidate();
        }
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.id_btn_pre:
                if (mIndex <= 0) {
                    mIndex = mPies.length -1;
                } else {
                    mIndex = mIndex - 1;
                }
                animated(mIndex);
                break;
            case R.id.id_btn_next:
                if (mIndex >= mPies.length - 1) {
                    mIndex = 0;
                } else {
                    mIndex = mIndex + 1;
                }
                animated(mIndex);
                break;
        }
    }
    //旋转
    private void animated(int index) {
        if(mPies.length > 1) {
            mAnimatePieChartView.onAnimatedPie(index);
        }
    }

具体的实现和调用方式就这么多了。

自定义的属性和代码可查看具体代码地址。 代码地址

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018.05.15 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
相关产品与服务
图数据库 KonisGraph
图数据库 KonisGraph(TencentDB for KonisGraph)是一种云端图数据库服务,基于腾讯在海量图数据上的实践经验,提供一站式海量图数据存储、管理、实时查询、计算、可视化分析能力;KonisGraph 支持属性图模型和 TinkerPop Gremlin 查询语言,能够帮助用户快速完成对图数据的建模、查询和可视化分析。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档