Android 自定义扇形统计图

public class ArcView extends View {

    private int mHeight, mWidth;//宽高
    private Paint mPaint;//扇形的画笔
    private Paint mTextPaint;//画文字的画笔

    private int centerX, centerY;//中心坐标

    //"其他"的value
    //扇形图分成太多快 所以要合并一部分为其他 即图中灰色部分
    private double rest;

    private int maxNum;//扇形图的最大块数 超过的item就合并到其他

    String others = "其他";//“其他”块要显示的文字
    double total;//数据的总和
    double[] datas;//数据集
    String[] texts;//每个数据对应的文字集

    //颜色 默认的颜色
    private int[] mColors = {
            Color.parseColor("#FF4081"), Color.parseColor("#ffc0cb"),
            Color.parseColor("#00ff00"), Color.parseColor("#0066ff"), Color.parseColor("#ffee00")
    };

    private int mTextSize;//文字大小

    private int radius = 1000;//半径

    public ArcView(Context context) {
        super(context);
    }

    public ArcView(Context context, AttributeSet attrs) {
        super(context, attrs);

        init();
    }

    //初始化
    private void init() {
        mPaint = new Paint();
        mPaint.setStrokeCap(Paint.Cap.ROUND);
        mPaint.setAntiAlias(true);

        mTextPaint = new Paint();
        mTextPaint.setTextSize(40);
        mTextPaint.setStrokeWidth(3);
        mTextPaint.setAntiAlias(true);
        mTextPaint.setColor(Color.BLACK);

        mTextSize = 30;
    }


    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        //获取宽高 不要设置wrap_content
        mHeight = MeasureSpec.getSize(heightMeasureSpec);
        mWidth = MeasureSpec.getSize(widthMeasureSpec);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //无数据
        if (datas == null || datas.length == 0) return;

        centerX = (getRight() - getLeft()) / 2;
        centerY = (getBottom() - getTop()) / 2;
        int min = mHeight > mWidth ? mWidth : mHeight;
        if (radius > min / 2) {
            radius = (int) ((min - getPaddingTop() - getPaddingBottom()) / 3.5);
        }

        //画扇形
        canvas.save();
        drawCircle(canvas);
        canvas.restore();


        //线与文字
        canvas.save();
        drawLineAndText(canvas);
        canvas.restore();

    }


    //画线与文字
    private void drawLineAndText(Canvas canvas) {
        int start = 0;
        canvas.translate(centerX, centerY);//平移画布到中心
        mPaint.setStrokeWidth(4);
        for (int i = 0; i < (maxNum < datas.length ? maxNum : datas.length); i++) {

            float angles = (float) ((datas[i] * 1.0f / total) * 360);
            drawLine(canvas, start, angles, texts[i], mColors[i % mColors.length]);
            start += angles;
        }
        //画其他
        if (start < 359)
            drawLine(canvas, start, 360 - start, others, Color.GRAY);

    }

    private void drawLine(Canvas canvas, int start, float angles, String text, int color) {
        mPaint.setColor(color);
        float stopX, stopY;
        stopX = (float) ((radius + 40) * Math.cos((2 * start + angles) / 2 * Math.PI / 180));
        stopY = (float) ((radius + 40) * Math.sin((2 * start + angles) / 2 * Math.PI / 180));

        canvas.drawLine((float) ((radius - 20) * Math.cos((2 * start + angles) / 2 * Math.PI / 180)),
                (float) ((radius - 20) * Math.sin((2 * start + angles) / 2 * Math.PI / 180)),
                stopX, stopY, mPaint
        );
        //画横线
        int dx;//判断横线是画在左边还是右边
        int endX;
        if (stopX > 0) {
            endX = (centerX - getPaddingRight() - 20);
        } else {
            endX = (-centerX + getPaddingLeft() + 20);
        }
        //画横线
        canvas.drawLine(stopX, stopY,
                endX, stopY, mPaint
        );
        dx = (int) (endX - stopX);

        //测量文字大小
        Rect rect = new Rect();
        mTextPaint.getTextBounds(text, 0, text.length(), rect);
        int w = rect.width();
        int h = rect.height();
        int offset = 20;//文字在横线的偏移量
        //画文字
        canvas.drawText(text, 0, text.length(), dx > 0 ? stopX + offset : stopX - w - offset, stopY + h, mTextPaint);

        //测量百分比大小
        String percentage = angles / 3.60 + "";
        percentage = percentage.substring(0, percentage.length() > 4 ? 4 : percentage.length()) + "%";
        mTextPaint.getTextBounds(percentage, 0, percentage.length(), rect);
        w = rect.width() - 10;
        //画百分比
        canvas.drawText(percentage, 0, percentage.length(), dx > 0 ? stopX + offset : stopX - w - offset, stopY - 5, mTextPaint);

    }

    //画扇形
    private void drawCircle(Canvas canvas) {
        RectF rect = new RectF((float) (centerX - radius), centerY - radius,
                centerX + radius, centerY + radius);

        int start = 0;
        for (int i = 0; i < (maxNum < datas.length ? maxNum : datas.length); i++) {
            float angles = (float) ((datas[i] * 1.0f / total) * 360);
            mPaint.setColor(mColors[i % mColors.length]);
            canvas.drawArc(rect, start, angles, true, mPaint);
            start += angles;
        }
        //画"其他"
        rest = 0;
        for (int i = maxNum; i < datas.length; i++) {
            rest += datas[i];
        }
        float angles = (float) 360 - start;
        mPaint.setColor(Color.GRAY);
        canvas.drawArc(rect, start, angles, true, mPaint);

    }



    //setter
    public void setColors(int[] mColors) {
        this.mColors = mColors;
        invalidate();
    }

    public void setTextSize(int mTextSize) {
        this.mTextSize = mTextSize;
        mTextPaint.setTextSize(mTextSize);
        invalidate();
    }

    public void setRadius(int radius) {
        this.radius = radius;
        setTextSize(radius / 6);
        invalidate();
    }

    public void setMaxNum(int maxNum) {
        this.maxNum = maxNum;
        invalidate();
    }

    public void setOthersText(String others) {
        this.others = others;
    }

    public abstract class ArcViewAdapter<T> {

        public void setData(List<T> list) {
            datas = new double[list.size()];
            texts = new String[list.size()];
            for (int i = 0; i < list.size(); i++) {
                total += getValue(list.get(i));
                datas[i] = getValue(list.get(i));
                texts[i] = getText(list.get(i));
            }

        }

        //通过传来的数据集的某个元素  得到具体的数字
        public abstract double getValue(T t);

        //通过传来的数据集的某个元素  得到具体的描述
        public abstract String getText(T t);
    }

}

//Activity中调用

List<Times> times = new ArrayList<>();
Times studentT = new Times();
studentT.hour = studentsSituation.getMatureStudents();//即将到期学员
studentT.text = "";

Times studentT1 = new Times();
studentT1.hour = studentsSituation.getExperiencedStudents();//体验学员
studentT1.text = "";

Times studentT2 = new Times();
studentT2.hour = studentsSituation.getFormalStudents();//正式学员
studentT2.text = "";

times.add(studentT);
times.add(studentT1);
times.add(studentT2);

getmyAdapter(times, arc1);
public void getmyAdapter(List<Times> times, ArcView mArcView) {
    ArcView.ArcViewAdapter myAdapter = mArcView.new ArcViewAdapter<Times>() {
        @Override
        public double getValue(Times times) {
            return times.hour;
        }

        @Override
        public String getText(Times times) {
            return times.text;
        }
    };//设置adapter
    myAdapter.setData(times);//设置数据集
    mArcView.setMaxNum(times.size());//设置可以显示的最大数值 该数值之后的会合并为其他

}
class Times {
    int hour;
    String text;
}

//布局调用

<teacher_administration.com.mvp.view.weigview.ArcView

android:id="@+id/arc2"

android:layout_width="match_parent"

android:layout_height="244dp" android:visibility="gone" />

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 可以使用Android提供的Canvas和Paint类来绘制空心扇形统计。具体步骤如下: 1. 创建一个继承自View的自定义View,重写onDraw方法。 2. 在onDraw方法中创建一个Paint对象,设置画笔的颜色和样式,如: ``` Paint paint = new Paint(); paint.setColor(Color.BLUE); paint.setStyle(Paint.Style.STROKE); paint.setStrokeWidth(5); ``` 3. 使用Canvas的drawArc方法来绘制扇形,需要传入扇形的矩形区域、起始角度和扫过的角度。如: ``` RectF rectF = new RectF(100, 100, 500, 500); canvas.drawArc(rectF, 0, 90, false, paint); ``` 其中,RectF对象用于指定扇形的位置和大小,前两个参数是左上角的坐标,后两个参数是右下角的坐标。第三个参数是起始角度,第四个参数是扫过的角度,第五个参数指定是否连接中心点。 4. 如果要绘制多个扇形,可以根据数据计算每个扇形的起始角度和扫过的角度。如: ``` float[] data = {30, 40, 50, 60}; float sum = 0; for (float value : data) { sum += value; } float startAngle = 0; for (float value : data) { float sweepAngle = value / sum * 360; canvas.drawArc(rectF, startAngle, sweepAngle, false, paint); startAngle += sweepAngle; } ``` 其中,data数组保存了每个扇形的数值,sum是所有数值的和,startAngle表示当前扇形的起始角度,sweepAngle表示当前扇形扫过的角度。 5. 最后,在布局文件中将自定义View添加到布局中即可。 以上是绘制空心扇形统计的基本步骤,具体细节可以根据需要进行调整。 ### 回答2: 要实现Android定义空心扇形统计,你可以使用自定义View来绘制扇形和文字。 首先,创建一个继承自View的自定义View类,命名为PieChartView。在该类的构造方法中,初始化画笔和相关属性,如颜色、宽度等。 接下来,在PieChartView的onMeasure方法中确定View的大小,这取决于父容器给出的测量要求。 在PieChartView的onDraw方法中,使用Canvas和Paint来绘制扇形和文字。根据给定的数据,计算出每个扇形所占的角度,然后根据角度和颜色依次绘制扇形。 为了实现空心效果,你可以使用Canvas的drawArc方法来绘制空心扇形,设置Paint的Style为STROKE,并设置边框的宽度。这样,只会绘制扇形的边框而不会填充颜色。 接着,在绘制扇形时,你可以通过设置一个起始角度来绘制每个扇形,使它们按顺时针或逆时针排列。绘制文字时,可以根据扇形的中心角度和半径来确定文字的位置。 最后,你需要在使用PieChartView的Activity或Fragment中设置相关数据,如每个扇形的角度和颜色。然后将PieChartView添加到布局中。 通过这些步骤,你就能够实现一个简单的Android定义空心扇形统计。当然,你还可以进一步定制化,添加动画效果或触摸交互等功能,使统计更加生动和实用。 ### 回答3: Android定义空心扇形统计可以通过继承View类,重写onDraw方法来实现。具体步骤如下: 1. 在XML布局文件中,声明一个自定义View的容器,如LinearLayout或RelativeLayout。 2. 在Java代码中,创建一个继承自View的类,重写onDraw方法。 3. 在onDraw方法中,先通过Canvas对象绘制一个圆形。 4. 再通过Path对象绘制一个扇形,可以通过Path.addArc方法来实现。 5. 设置扇形的起始角度和扇形的角度大小,可以根据所需的数据来计算。 6. 设置扇形的颜色,可以通过Paint对象的setColor方法来设置。 7. 设置扇形的样式为空心,可以通过Paint对象的setStyle方法来设置。 8. 设置扇形的边框宽度和颜色,可以通过Paint对象的setStrokeWidth和setColor方法来设置。 9. 最后调用Canvas对象的drawPath方法来绘制扇形。 10. 在主Activity中,实例化自定义View类的对象,并将其添加到容器中。 通过以上步骤,就可以实现一个自定义的空心扇形统计。可以根据需要来设置扇形的起始角度、角度大小、颜色和边框样式等属性,以达到所需的效果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值