美文网首页
Android笔记——自定义View之饼图与柱状图

Android笔记——自定义View之饼图与柱状图

作者: 麦香菌 | 来源:发表于2018-12-07 16:52 被阅读0次

    因为一直喜欢琢磨界面,所以总爱翻跟界面有关的文章。之前在HenCoder上看到自定义View的教学,就跟着敲出了饼图和柱状图:


    饼图
    柱状图

    一、饼图

    1、数据初始化

    饼图绘制的关键是角度,获取数据后将各个数据在总数中的占比转化成角度进行绘制。

          /*数据总和*/
            sum = 0;
          /*饼图每部分开始绘制的角度*/
            startAngle = 0;
          /*饼图每部分结束绘制的角度*/
            endAngle = 0;
          /*获取数值总和,最大数值及其下标*/
            for (int i=0;i<values.length;i++) {
                sum+=values[i];
                if(values[i]>=maxValue){
                    maxValue = values[i];
                    maxIndex = i;
                    Log.d(TAG,"maxValue:"+maxValue);
                    Log.d(TAG,"maxIndex:"+maxIndex);
                }
            }
            Log.d(TAG,"sum:"+sum);
            textPaint = new Paint();
            paint = new Paint();
            path = new Path();
            paint.setAntiAlias(true);/*开启抗锯齿*/
    

    2、绘制数值

    获取画布的宽高,设置恰当的半径,开始绘制。

    if(values.length>0&&values.length==datas.length){
                init();
                int width = getWidth();
                int height = getHeight();
                int r = Math.min(width,height)/2;
    
                paint.setStyle(Paint.Style.STROKE);
                paint.setColor(textColor);
                paint.setStrokeWidth(strokeWidth);
                textPaint.setTextSize(percentSize);
                /*圆的半径*/
                int R = (int)(r- r*0.15f);
    
                /*绘制数值*/
                for (int i=0; i<values.length; i++){
                    float percent = values[i]/sum;
                    startAngle = endAngle;
                    endAngle+=360 * percent;
                    angle = endAngle - startAngle;
                    Log.d(TAG,"startAngle:"+startAngle);
                    Log.d(TAG,"endAngle:"+endAngle);
                    Log.d(TAG,"angle:"+angle);
                    /*判断是否在绘制最大值的文字*/
                    xMaxOffset = maxIndex==i?offset*(float)Math.cos(Math.toRadians(startAngle+angle/2)):0;
                    yMaxOffset = maxIndex==i?offset*(float)Math.sin(Math.toRadians(startAngle+angle/2)):0;
                    float xOffset = (offset+DensityUtil.dip2px(getContext(),2))
                            *(float)Math.cos(Math.toRadians(startAngle+angle/2));
                    float yOffset = (offset+DensityUtil.dip2px(getContext(),2))
                            *(float)Math.sin(Math.toRadians(startAngle+angle/2));
                    Log.d(TAG,"xMaxOffset:"+xMaxOffset);
                    Log.d(TAG,"yMaxOffset:"+yMaxOffset);
                    x = R*(float)Math.cos(Math.toRadians(startAngle+angle/2));
                    y = R*(float)Math.sin(Math.toRadians(startAngle+angle/2));
                    path.moveTo(width/2+xOffset+xMaxOffset+x*0.3f,height/2+yOffset+yMaxOffset+y*0.3f);
                    path.rLineTo(x*0.7f,y*0.7f);
                    canvas.drawPath(path,paint);
                    if(startAngle+angle/2>90&&startAngle+angle/2<270){
                        path.rLineTo(-stripValue,0);
                        textPaint.setTextAlign(Paint.Align.RIGHT);
                        canvas.drawText(String.format("%.2f", percent*100)+"%",
                                width/2+x-text2strip+xOffset+xMaxOffset,height/2+y+yOffset+yMaxOffset,textPaint);
                    }else {
                        path.rLineTo(stripValue,0);
                        textPaint.setTextAlign(Paint.Align.LEFT);
                        canvas.drawText((String.format("%.2f", percent*100))+"%",
                                width/2+x+text2strip+xOffset+xMaxOffset,height/2+y+yOffset+yMaxOffset,textPaint);
                    }
                    canvas.drawPath(path,paint);
                }
    

    3、绘制饼图和文字

    衔接上面的代码开始绘制饼图和文字

                /*绘制饼图*/
                startAngle=endAngle=angle=0;
                paint.setStyle(Paint.Style.FILL);
                RectF oval=new RectF();                     //RectF对象
                for (int i=0; i<values.length; i++){
                    float percent = values[i]/sum;
                    startAngle = endAngle;
                    endAngle+=360 * percent;
                    angle = endAngle - startAngle;
                    /*最大一部分的xy轴偏移量*/
                    xMaxOffset = maxIndex==i?offset*(float)Math.cos(Math.toRadians(startAngle+angle/2)):0;
                    yMaxOffset = maxIndex==i?offset*(float)Math.sin(Math.toRadians(startAngle+angle/2)):0;
                    /*饼图每一部分的偏移量,这样才能绘制出缝隙*/
                    float xOffset = offset*(float)Math.cos(Math.toRadians(startAngle+angle/2));
                    float yOffset = offset*(float)Math.sin(Math.toRadians(startAngle+angle/2));
                    oval.left=width/2-r+r*PIE_PERCENT+xOffset+xMaxOffset;  //左边
                    oval.top=height/2-r+r*PIE_PERCENT+yOffset+yMaxOffset;  //上边
                    oval.right=width/2+r-r*PIE_PERCENT+xMaxOffset; //右边
                    oval.bottom=height/2+r-r*PIE_PERCENT+yMaxOffset;   //下边
    
                    /*防止最后一部分与第一部分的颜色重叠*/
                    if (i==values.length-1&&i%ChartColor.COLORNUMMBER==0){
                        paint.setColor(colors[i%ChartColor.COLORNUMMBER+1]);
                    }else {
                        paint.setColor(colors[i%ChartColor.COLORNUMMBER]);
                    }
                    
                    canvas.drawArc(oval,startAngle,angle,true,paint);
                    x = (R)*(float)Math.cos(Math.toRadians(startAngle+angle/2));
                    y = (R)*(float)Math.sin(Math.toRadians(startAngle+angle/2));
                    textPaint.setTextAlign(Paint.Align.CENTER);
                }
    
                /*为防止饼图的最后一部分将第一个文字覆盖,将文字的绘制独立了出来*/
                for (int i=0; i<values.length; i++){
                    float percent = values[i]/sum;
                    startAngle = endAngle;
                    endAngle+=360 * percent;
                    angle = endAngle - startAngle;
                    x = (R)*(float)Math.cos(Math.toRadians(startAngle+angle/2));
                    y = (R)*(float)Math.sin(Math.toRadians(startAngle+angle/2));
                    textPaint.setTextSize(textSize);
                    canvas.drawText(datas[i],width/2+x*2/3,height/2+y*2/3,textPaint);
                }
            }
    

    二、柱状图

    柱状图就是绘制矩形和xy轴,难点是沿着y轴绘制y轴坐标名称,解决的办法是沿折线绘制文字。

    1、数据初始化

    /*获取最大数值*/
            for (float value : values) {
                if(value >= max){
                    max = value;
                }
            }
            /*画布宽高*/
            width = getWidth();
            height = getHeight();
            /*每个柱子间的间隙*/
            spacing = (width-2*marginLeft)*0.3f/(values.length+1);
            /*柱子的宽度*/
            bgWidth = (width-2*marginLeft)*0.7f/(values.length);
            /*柱子的最高高度*/
            maxHeight = height-5*marginBottom;
            /*y轴距左边缘的偏移值*/
            leftOffset = (unit!=""&&Yname!="") ? DensityUtil.dip2px(getContext(),10):0;
    

    2、绘制xy轴与y轴坐标名称

                /*绘制xy轴*/
                path = new Path();
                paint = new Paint();
                textPaint = new Paint();
                textPaint.setTextSize(textSize);
                textPaint.setTextAlign(Paint.Align.CENTER);
                paint.setStyle(Paint.Style.STROKE);
                path.moveTo(marginLeft+leftOffset,marginBottom);
                path.rLineTo(0,height-3*marginBottom);
                canvas.drawPath(path,paint);
    
                /*绘制y轴坐标名称*/
                if(unit!=""&&Yname!=null){
                    canvas.drawTextOnPath(Yname+"/"+unit,path,-(height-10*marginBottom)/2,textSize*3/2,textPaint);
                }
                path.rLineTo(width-2*marginLeft,0);
                canvas.drawPath(path,paint);
    

    3、绘制柱子和数据

    /*绘制柱子和文字*/
                startXposition = marginLeft+spacing+leftOffset;
                startYposition = marginBottom+height-3*marginBottom;
                paint.setStyle(Paint.Style.FILL);
                paint.setColor(ChartColor.VIOLETRED);
    
                /*柱子的左上角与右下角*/
                float left = 0;
                float top = 0;
                float right = 0;
                float bottom = 0;
                int i = 0;
                for (float value : values) {
                    left = startXposition;
                    top = startYposition - value/max * maxHeight;
                    right = startXposition + bgWidth;
                    bottom = startYposition;
                    canvas.drawRect(left,top,right,bottom,paint);
                    canvas.drawText(String.valueOf(value),startXposition+bgWidth/2,top-marginBottom/2,textPaint);
                    canvas.drawText(datas[i],startXposition+bgWidth/2,startYposition+marginBottom*3/2,textPaint);
                    startXposition = startXposition + spacing + bgWidth;
                    i++;
                }
    

    三、使用

    1、添加依赖


    2.饼图

    在xml里添加布局

    <com.mils.mychart.chart.PieChartView
            android:id="@+id/pc"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"/>
    

    添加数据与数据名称

    float[] values = new float[]{5,2,7,25,40,20,30,10,10,4,10,4};
    String[] datas = new String[]{"语文","数学","英语","文综","理综","数学","英语","文综","理综","理综","文综","理综"};
    pcView.setValues(values);
    pcView.setDatas(datas);
    

    设置文字与数值字体大小,默认为10dp

    pcView.setPercentSize(10f);
    pcView.setTextSize(10f);
    

    3、柱状图

    在xml里添加布局

    <com.mils.mychart.chart.BarGraphView
            android:id="@+id/bg"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"/>
    

    添加数据与数据名称

    float[] values = new float[]{5,2,7,25,40,20,30,10,10,4,10,4};
    String[] datas = new String[]{"语文","数学","英语","文综","理综","数学","英语","文综","理综","理综","文综","理综"};
    bgView.setValues(values);
    bgView.setData(datas);
    

    添加y轴坐标单位与名称

    bgView.setYaxis("分","分数");        
    

    设置柱状图颜色

    bgView.setChartColor(ChartColor.ORANGEYELLOW);
    

    END

    github地址:https://github.com/Mils-liu/MyChart
    HenCoder教程地址:https://hencoder.com/activity-mock-2/

    相关文章

      网友评论

          本文标题:Android笔记——自定义View之饼图与柱状图

          本文链接:https://www.haomeiwen.com/subject/nubthqtx.html