zoukankan      html  css  js  c++  java
  • 自定义View饼状图的绘制

    package com.loaderman.customviewdemo;
    
    import android.content.Context;
    import android.graphics.Canvas;
    import android.graphics.Color;
    import android.graphics.Paint;
    import android.graphics.RectF;
    import android.util.AttributeSet;
    import android.view.View;
    
    import java.text.DecimalFormat;
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * Created by MQ on 2016/12/15.
     */
    
    public class CakeView extends View {
        //装载的饼状圆数据
        private List<CakeBean> beanList;
        //画圆的矩形
        private RectF          mRectF;
        //右边的小矩形
        private RectF          iRectF;
        private Paint          mPaint;
        private int            mRWidth, mRHeight;
        private float rotateDegree;//每个圆弧的起始角度
        private float sumValue = 0;//所有值的和
        private float diameter;//圆的直径
        private float textY;//绘制文字的Y坐标
    
        private float mRectHeight = 40;//矩形高度
        private float mRectWidth = 80;//矩形宽度
        private float mMargin = 40;//矩形和圆的距离
        private Context mContext;
    
        public CakeView(Context context) {
            //CakeView cakeView=new CakeView(context);
            // 在代码中new CakeView()会调用这个构造函数
            this(context, null);
        }
    
        public CakeView(Context context, AttributeSet attrs) {
            //InflateLayoutManager时会调用这个构造函数
            this(context, attrs, 0);
        }
    
        public CakeView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            mContext = context;
            init();
        }
    
        private void init() {
            beanList = new ArrayList<>();
            mRectF = new RectF();
            mPaint = new Paint();
            mPaint.setAntiAlias(true);
            mPaint.setDither(true);
        }
    
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            //MeasureSpec封装了父View传递给子View的布局要求
            int wMode = MeasureSpec.getMode(widthMeasureSpec);
            int wSize = MeasureSpec.getSize(widthMeasureSpec);
            int hMode = MeasureSpec.getMode(heightMeasureSpec);
            int hSize = MeasureSpec.getSize(heightMeasureSpec);
            switch (wMode) {
                case MeasureSpec.EXACTLY:
                    //相当于match_parent或者一个具体值
                    mRWidth = wSize;
                    break;
                case MeasureSpec.AT_MOST:
                    // 相当于wrap_content 默认会充满父View
                    // 可以根据子View的大小来计算父View大小,这里先写死大小
                    mRWidth = (int) DpUtil.dp2px(mContext, 400f);
                    break;
                case MeasureSpec.UNSPECIFIED:
                    //很少会用到
                    break;
                default:
                    break;
            }
            switch (hMode) {
                case MeasureSpec.EXACTLY:
                    //相当于match_parent或者一个具体值
                    mRHeight = hSize;
                    break;
                case MeasureSpec.AT_MOST:
                    // 相当于wrap_content 默认会充满父View
                    // 可以根据子View的大小来计算父View大小,这里先写死大小
                    mRHeight = (int) DpUtil.dp2px(mContext, 200f);
                    break;
                case MeasureSpec.UNSPECIFIED:
                    //很少会用到
                    break;
                default:
                    break;
            }
            //存储测量好的宽和高
            setMeasuredDimension(wSize, hSize);
        }
    
        @Override
        protected void onSizeChanged(int w, int h, int oldw, int oldh) {
            super.onSizeChanged(w, h, oldw, oldh);
            diameter = Math.min(mRWidth, mRHeight);
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            textY = 0f;
            //设置圆形绘制的范围
            mRectF.set(0, 0, diameter, diameter);
            //画布中心X坐标向右移动(控件宽度-圆直径)之差的八分之一的距离
            //画布中心Y坐标向下移动(控件宽度-圆直径)之差的二分之一的距离
            canvas.translate((mRWidth - diameter) / 8, (mRHeight - diameter) / 2);
            if (beanList.size() > 0 && Float.compare(sumValue, 0.0f) != 0) {
                for (int i = 0; i < beanList.size(); i++) {
                    CakeBean bean = beanList.get(i);
                    //画圆弧
                    mPaint.setColor(bean.mColor);
                    canvas.drawArc(mRectF, rotateDegree, bean.degree, true, mPaint);
                    rotateDegree += bean.degree;
                    //画矩形和文字
                    drawRectAndText(canvas, bean);
                }
            }
        }
    
        private void drawRectAndText(Canvas canvas, CakeBean bean) {
            iRectF = new RectF();
            //设置画矩形的范围
            float left = diameter + mMargin;
            float right = diameter + mMargin + mRectWidth;
            float bottom = textY + mRectHeight;
            iRectF.set(left, textY, right, bottom);
            canvas.drawRect(iRectF, mPaint);
            //设置颜色
            mPaint.setColor(Color.BLACK);
            //设置文字大小
            mPaint.setTextSize(30);
            //画文字
            canvas.drawText(bean.name + "(" + new DecimalFormat(".00").format(bean.value / sumValue * 100) + "%)", right + 10, textY + 30, mPaint);
            textY += mRectHeight;
        }
    
        /**
         * 饼状图添加数据
         *
         * @param beans CakeBean数据
         */
        public void setData(List<CakeBean> beans) {
            if (beans == null || beans.size() <= 0) return;
            for (int i = 0; i < beans.size(); i++) {
                CakeBean bean = beans.get(i);
                sumValue += bean.value;
            }
            for (int i = 0; i < beans.size(); i++) {
                CakeBean bean = beans.get(i);
                bean.degree = bean.value / sumValue * 360;
                beanList.add(bean);
            }
            invalidate();
        }
    
        /**
         * @param startDegree 设置起始角度
         */
        public void setStartDegree(float startDegree) {
            this.rotateDegree = startDegree;
            invalidate();
        }
    }
    
    package com.loaderman.customviewdemo;
    
    import java.io.Serializable;
    
    public class CakeBean implements Serializable {
        public String name;//名字
        public float value;//值
        public float degree;//旋转过的角度
        public int mColor;//圆弧颜色
    }
    
    package com.loaderman.customviewdemo;
    
    import android.app.Activity;
    import android.content.Context;
    import android.util.DisplayMetrics;
    
    /**
     * Created by MQ on 2016/12/16.
     */
    
    public class DpUtil {
        /**
         * dp转换成px
         *
         * @param context Context
         * @param dp      dp
         * @return px值
         */
        public static float dp2px(Context context, float dp) {
            final float scale = context.getResources().getDisplayMetrics().density;
            return dp * scale + 0.5f;
        }
    
        /**
         * sp转换成px
         *
         * @param context Context
         * @param sp      sp
         * @return px值
         */
        public static float sp2px(Context context, float sp) {
            final float scale = context.getResources().getDisplayMetrics().scaledDensity;
            return sp * scale;
        }
    
        /**
         * 获得屏幕宽度
         *
         * @param context Context
         * @return 屏幕宽度(像素)
         */
        public static int getScreenSizeWidth(Context context) {
            DisplayMetrics metric = new DisplayMetrics();
            ((Activity) context).getWindowManager().getDefaultDisplay().getMetrics(metric);
            return metric.widthPixels;
        }
    }
    
    package com.loaderman.customviewdemo;
    
    import android.graphics.Color;
    import android.os.Bundle;
    import android.support.v7.app.AppCompatActivity;
    
    import java.util.ArrayList;
    import java.util.List;
    
    public class MainActivity extends AppCompatActivity {
        private List<CakeBean> beans;
        private String[] names = {"php", "object-c", "c", "c++", "java", "android", "linux"};
        private float[] values = {2f, 2f, 3f, 4f, 5f, 6f, 7f};
        private int[] colArrs = {Color.RED, Color.parseColor("#4ebcd3"), Color.MAGENTA, Color.YELLOW, Color.GREEN, Color.parseColor("#f68b2b"), Color.parseColor("#6fb30d")};//圆弧颜色
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            CakeView cake_view = (CakeView) findViewById(R.id.cake_view);
            initData();
            cake_view.setData(beans);
    
    
        }
    
        private void initData() {
            beans = new ArrayList<>();
            for (int i = 0; i < 7; i++) {
                CakeBean bean = new CakeBean();
                bean.name = names[i];
                bean.value = values[i];
                bean.mColor = colArrs[i];
                beans.add(bean);
            }
        }
        
    }
    

     效果图:

  • 相关阅读:
    ActiveMQ的消息模式——队列模式(Queue)
    在foxmail上添加阿里邮箱
    Neither the JAVA_HOME nor the JRE_HOME environment variable is defined 错误解决
    博客园首页新随笔联系管理订阅订阅随笔- 89 文章- 0 评论- 3 Centos7开放及查看端口
    tomcat设置为开机自启动
    Tensorflow2疑难问题---2、tensorflow2.3的GPU版本安装
    Tensorflow2疑难问题---1、课程介绍
    tensorflow2的gpu的版本安装(一些核心点)
    此环境变量太大, 此对话框允许将值设置为最长2047个字符(解决方法)
    windows下cuda的安装
  • 原文地址:https://www.cnblogs.com/loaderman/p/7017442.html
Copyright © 2011-2022 走看看