android 自定义百分比饼图

先上图

普通效果

点击效果,点击之后会放大半径

实现百分比圆饼,整体步骤分为

1.先根据数据集占的百分比画圆弧,使用不同颜色,很简单

2.然后设置点击重绘圆饼,判断点击区域在不在圆上,如果在圆上,那么在具体的哪个圆弧上面

上代码:直接拿去使用即可

package com.cnki.roundcake;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Region;
import android.graphics.RegionIterator;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

import java.util.ArrayList;

/**
 * 百分比圆饼图
 * Created by liweidong on 2019/12/2.
 */

public class RoundCake extends View{

    //数据集
    private ArrayList<CakeBean> mCakeBean;
    private Paint paint;
    //半径
    private int radius = 150;
    private RectF rectF;
    private RectF rectFTouch;
    //画百分比时每次的开始角度
    private float startRadius;
    private float mCurX;
    private float mCurY;
    private Paint regionPaint;

    public RoundCake(Context context) {
        super(context);
        init();
    }

    public RoundCake(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public RoundCake(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    /**
     * 初始化
     */
    private void init(){
        mCurX = -1;
        mCurY = -1;
        startRadius = 0;
        paint = new Paint();
        paint.setStyle(Paint.Style.FILL);
        paint.setStrokeWidth(5);
        //初始化圆饼矩形
        rectF = new RectF(20,20, radius * 2, radius * 2);
        rectFTouch = new RectF(0,0, radius * 2 + 20, radius * 2 + 20);

        regionPaint = new Paint();
        regionPaint.setColor(Color.WHITE);
        regionPaint.setStyle(Paint.Style.FILL_AND_STROKE);
        regionPaint.setStrokeWidth(2);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        startRadius = 0;
        //首先判断是否在圆内
        if (mCurX != -1){
            if ( ((mCurX - radius) * (mCurX - radius) + (mCurY - radius) * (mCurY - radius)) < radius * radius){
                //画饼图
                for (int i = 0; i < mCakeBean.size(); i++){
                    paint.setColor(mCakeBean.get(i).getColor());
                    if (isContainPoint(canvas,i)){
                        canvas.drawArc(rectFTouch, startRadius + 5 , mCakeBean.get(i).getRadius() - 10, true, paint);
                    }else{
                        canvas.drawArc(rectF, startRadius, mCakeBean.get(i).getRadius(), true, paint);
                    }
                    startRadius +=  mCakeBean.get(i).getRadius();
                }
                return;
            }
        }
        //画饼图
        for (int i = 0; i < mCakeBean.size(); i++){
            paint.setColor(mCakeBean.get(i).getColor());
            canvas.drawArc(rectF, startRadius, mCakeBean.get(i).getRadius(), true, paint);
            startRadius +=  mCakeBean.get(i).getRadius();
        }
    }

    /**
     * 判断圆弧区域内是否包含某点
     * @param i
     * @return
     */
    private boolean isContainPoint(Canvas canvas,int i){
        Path path = new Path();
        path.moveTo(radius + 10, radius + 10);
        if (i == 0){
            path.lineTo(3 * radius + 10, radius + 10);
        }else{
            path.lineTo((float) (radius + 20 + 2*radius * Math.cos(Math.toRadians(startRadius))),
                    (float) (radius + 20 + 2*radius * Math.sin(Math.sin(Math.toRadians(startRadius)))));
        }
        path.lineTo((float) (radius + 20 + 2*radius * Math.cos(Math.toRadians(startRadius + mCakeBean.get(i).getRadius()))),
                (float) (radius + 20 + 2*radius * Math.sin(Math.sin(Math.toRadians(startRadius + mCakeBean.get(i).getRadius())))));
        path.close();
        Region region = new Region();
        region.setPath(path, new Region(new Rect(20, 20, radius * 2, radius * 2)));
        /*RegionIterator regionIterator = new RegionIterator(region);
        Rect rect = new Rect();
        while (regionIterator.next(rect)){
            canvas.drawRect(rect, paint);
        }*/
        return region.contains((int)mCurX, (int)mCurY);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        mCurX = event.getX();
        mCurY = event.getY();
        switch (event.getAction()){
            case MotionEvent.ACTION_DOWN:
                invalidate();
                return true;
            case MotionEvent.ACTION_UP:
                mCurX = -1;
                mCurY = -1;
        }
        invalidate();
        return super.onTouchEvent(event);
    }

    /**
     * 设置数据给饼图
     * @param cakes
     */
    public void setCakes(ArrayList<CakeBean> cakes){
        this.mCakeBean = cakes;
        invalidate();
    }
}

以上就是核心自定义类的代码,主要难点在于点击换圆弧的半径,可以重点看一下代码,实现的逻辑是根据数学公式x平方 + y平方 < 半径的平方,那么判断是在圆上;第二步如果判断在圆上的话,运用region知识,求交集区域(尽可能把交集区域加大)

发布了10 篇原创文章 · 获赞 7 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/no_loafer/article/details/103373686
今日推荐