自定义圆形统计图(静态)

42 篇文章 1 订阅
28 篇文章 0 订阅

    最近项目中有这个需求,将总资产的组成以图形的形态展现出来,所以就写了个自定义View来实现这个需求。


    其实试下这个思路还是挺简单的,因为只需要在onDraw方法中使用画笔画出一个又一个的扇形,就能实现这样的效果。

    以下是我的思路,首先介绍下canvas.drawArc()方法。

    RectF rectF = new RectF(100, 100, 500, 500);
    //绘制扇形
    canvas.drawArc(rectF, startAngle, endAngle, true, paint);

    参数说明:

    rectF:绘制扇形的区域

    startAngle:扇形的开始绘制的角度(是角度值不是弧度值)

    endAngle:扇形绘制结束的角度值

    true:是否从圆心开始画扇形

    paint:画笔

    所以实现起来的思路就是:

    通过给定的数据值,也就是一个包含数字的数组,然后算出每个数字的比重,乘上360度,算出每个数字所占的扇形的角度值,然后通过给不同数字的画上颜色不同的扇形,当处理完所有的数据后,就可以看到由不同颜色扇形所组成的一个圆,这当然不是我们所想要的,所以在最后,以相同的圆心画一个白色的圆,当然这个圆的半径要比刚刚那个彩色的圆的半径要小,最后剩下的就是我们想要的结果,最后在扇形的中间写上我们需要的文字即可。

    这个是画上几个扇形后的效果。


在中间画一个白色的圆之后就变成这样的了


其实这个时候就已经初见成效了。最后加上文字就好了。


最后提供自定义的控件。

SelfStatistics.java

package com.cretin.testprogress.views;

import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.os.Build;
import android.util.AttributeSet;
import android.view.View;

import java.util.ArrayList;
import java.util.List;

/**
* Created by cretin on 16/6/23.
*/
public class SelfStatistics extends View {
   private Paint paint;
   //对外提供注入数据的变量
   private float[] datas;
   //自定义view内部存储数据信息
   private List<Infos> listDatas = new ArrayList<>();
   //默认统计图的颜色配置 如果数据大于4 则颜色轮询
   private String colorRes[] = new String[]{"#fdb128", "#4a90e2", "#89c732", "#f46950"};
   private int mPanelWidth;

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

   private void init() {
       paint = new Paint();
   }

   public SelfStatistics(Context context, AttributeSet attrs) {
       super(context, attrs);
       init();
   }

   public SelfStatistics(Context context, AttributeSet attrs, int defStyleAttr) {
       super(context, attrs, defStyleAttr);
       init();
   }

   @TargetApi(Build.VERSION_CODES.LOLLIPOP)
   public SelfStatistics(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
       super(context, attrs, defStyleAttr, defStyleRes);
       init();
   }

   public float[] getDatas() {
       return datas;
   }

   public void startDraw() {
       invalidate();
   }

   public void setDatas(float[] datas) {
       this.datas = datas;
   }

   @Override
   protected void onDraw(Canvas canvas) {
       super.onDraw(canvas);
       if (datas != null && datas.length > 0) {
           calculateDatas();
           //获取圆心的x坐标
           int center = mPanelWidth / 2;
           //圆环的半径
           int radius = center - 10;
           //消除锯齿
           paint.setAntiAlias(true);
           //给外圈设置样式
           paint.setStyle(Paint.Style.FILL_AND_STROKE);
           //设置StrokeWidth
           paint.setStrokeWidth(20);
           //给外圈设置颜色
           paint.setColor(Color.WHITE);
           //画最外层的圈
           canvas.drawCircle(center, center, radius, paint);
           //设置进度的颜色
           for (Infos infos : listDatas) {
           //定义一个RectF类
               paint.setColor(Color.parseColor(infos.getColor()));
               RectF rectF = new RectF(center - radius, center - radius, center + radius, center + radius);
               //绘制扇形
               canvas.drawArc(rectF, infos.getStartAngle(), infos.getEndAngle(), true, paint);
           }
            //画最外层的圈
           paint.setColor(Color.WHITE);
           canvas.drawCircle(center, center, radius - 50, paint);

           drawTexts(canvas, center);
       }
   }

   @Override
   protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
       int widthSize = MeasureSpec.getSize(widthMeasureSpec);
       int widthMode = MeasureSpec.getMode(widthMeasureSpec);

       int heightSize = MeasureSpec.getSize(heightMeasureSpec);
       int heightMode = MeasureSpec.getMode(heightMeasureSpec);

       int width = Math.min(widthSize, heightSize);
       if (widthMode == MeasureSpec.UNSPECIFIED) {
           width = heightSize;
       } else if (heightMode == MeasureSpec.UNSPECIFIED) {
           width = widthSize;
       }
       setMeasuredDimension(width, width);
   }

   @Override
   protected void onSizeChanged(int w, int h, int oldw, int oldh) {
       super.onSizeChanged(w, h, oldw, oldh);
       mPanelWidth = Math.min(w,h);
   }

   private void drawTexts(Canvas canvas, int center) {
       float total = 0;
       for (int i = 0; i < datas.length; i++) {
           total += datas[i];
       }
       String totalStr = total + "元";
       paint.setStrokeWidth(2);
       //设置进度扇形的样式
       paint.setStyle(Paint.Style.FILL);
       //设置文字的大小
       paint.setTextSize(35);
       int widthStr1 = (int) paint.measureText("总资产");
       int widthStr2 = (int) paint.measureText(totalStr);
       paint.setColor(Color.parseColor("#333333"));
       float baseX = center - widthStr1 / 2;
       float baseY = center + 20 / 4;
       Paint.FontMetrics fontMetrics = paint.getFontMetrics();
       float fontTotalHeight = fontMetrics.bottom - fontMetrics.top;
       float offY = fontTotalHeight / 2 - fontMetrics.bottom - 30;
       float newY = baseY + offY;
       canvas.drawText("总资产", baseX, newY, paint);

       paint.setColor(Color.parseColor("#fc561f"));
       float baseX1 = center - widthStr2 / 2;
       float baseY1 = center + 20 / 4;
       Paint.FontMetrics fontMetrics1 = paint.getFontMetrics();
       float fontTotalHeight1 = fontMetrics1.bottom - fontMetrics1.top;
       float offY1 = fontTotalHeight1 / 2 - fontMetrics1.bottom + 30;
       float newY1 = baseY1 + offY1;
       canvas.drawText(totalStr, baseX1, newY1, paint);
   }

   //为绘画做基本的计算
   private void calculateDatas() {
       float total = 0;
       float tempAngle = 270;
       //计算出总数
       for (int i = 0; i < datas.length; i++) {
           total += datas[i];
       }
       //创建不同的Infos对象
       Infos infos;
       for (int i = 0; i < datas.length; i++) {
           infos = new Infos();
           float currData = datas[i];
           float startAngle = tempAngle;
           float endAngle = (float) (currData * 100 / total * 3.6);
           infos.setStartAngle(startAngle);
           infos.setEndAngle(endAngle);
           infos.setColor(colorRes[i % colorRes.length]);
           tempAngle = endAngle + tempAngle;
           listDatas.add(infos);
       }
   }

   class Infos {
       private float startAngle;
       private float endAngle;
       private String color;

       public String getColor() {
           return color;
       }

       public void setColor(String color) {
           this.color = color;
       }

       public float getStartAngle() {
           return startAngle;
       }

       public void setStartAngle(float startAngle) {
           this.startAngle = startAngle;
       }

       public float getEndAngle() {
           return endAngle;
       }

       public void setEndAngle(float endAngle) {
           this.endAngle = endAngle;
       }
   }
}


最后提供使用的方法:

布局文件:activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:tools="http://schemas.android.com/tools"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   tools:context="com.cretin.testprogress.MainActivity">

   <com.cretin.testprogress.views.SelfStatistics
       android:id="@+id/progress"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content" />
</RelativeLayout>


主函数的调用:

package com.cretin.testprogress;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

import com.cretin.testprogress.views.SelfStatistics;

public class MainActivity extends AppCompatActivity {

   private SelfStatistics selfStatistics;
   @Override
   protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.activity_main);

       selfStatistics = (SelfStatistics) findViewById(R.id.progress);
       float datas[] = new float[]{4000,3000,7000,8000};
       selfStatistics.setDatas(datas);
       selfStatistics.startDraw();
   }
}


最后我写了一个demo,欢迎下载,重在分享,不要积分哦,哈哈

下载地址为:http://download.csdn.net/detail/u010998327/9557747

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值