前言:继上次写了自定义圆形进度条后,今天给大家带来自定义扇形饼状图。先上效果图:
是不是很炫?看上去还有点立体感。下面带大家一起来瞧一瞧吧。
一、定义成员变量,重写构造方法
看着这个效果图,我们可以想象下接下来暂时会需要用到以下属性:
/**
* 存放事物的品种与其对应的数量
*/
private Map kindsMap = new LinkedHashMap<String, Integer>();
/**
* 存放颜色
*/
private ArrayList<Integer> colors = new ArrayList<>();
private Paint mPaint;//饼状画笔
private Paint mTextPaint; // 文字画笔
private static final int DEFAULT_RADIUS = 200;
private int mRadius = DEFAULT_RADIUS; //外圆的半径
private String centerTitle; //中间标题
然后重写父类的构造方法,初始化画笔:
public PieChatView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mPaint = new Paint();
mTextPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setStyle(Paint.Style.FILL);
mTextPaint.setColor(Color.BLACK);
mTextPaint.setAntiAlias(true);
mTextPaint.setStyle(Paint.Style.STROKE);
mTextPaint.setTextAlign(Paint.Align.CENTER);
}
public PieChatView(Context context) {
this(context, null, 0);
}
public PieChatView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
一般都是一个参数和两个参数的全部调用第三个参数的。我三个参数的构造方法中没有去从xml文件中去获取属性了。我完全就用代码实现了。也可以将一些属性放在attrs.xml文件中,然后去获取。自行选择吧。
二、onMeasure()
这个方法,只要你以前写过自定义View,基本上就是一样的套路:
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int wideSize = MeasureSpec.getSize(widthMeasureSpec);
int wideMode = MeasureSpec.getMode(widthMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int width, height;
if (wideMode == MeasureSpec.EXACTLY) { //精确值 或matchParent
width = wideSize;
} else {
width = mRadius * 2 + getPaddingLeft() + getPaddingRight();
if (wideMode == MeasureSpec.AT_MOST) {
width = Math.min(width, wideSize);
}
}
if (heightMode == MeasureSpec.EXACTLY) { //精确值 或matchParent
height = heightSize;
} else {
height = mRadius * 2 + getPaddingTop() + getPaddingBottom();
if (heightMode == MeasureSpec.AT_MOST) {
height = Math.min(height, heightSize);
}
}
setMeasuredDimension(width, height);
mRadius = (int) (Math.min(width - getPaddingLeft() - getPaddingRight(),
height - getPaddingTop() - getPaddingBottom()) * 1.0f / 2);
}
就是获得系统测量好的宽高,和模式后分三种模式去讨论。最终通过setMeasuredimension()确定宽高的值。宽高确定好了,那就可以确定下整个饼状图的半径 mRadius了。取宽高中的较小的那个。
三、onDraw();
我们需要画一个一个的扇形,还有将扇形从零到360的动画效果,还有扇形中的文字,中间的文字,还有实现立体感的效果。
1.画扇形。
画一个扇形还是蛮容易的:通过画布调用drawArc()方法话一个60度的扇形:
mPaint.setStyle(Paint.Style.FILL);
mTextPaint.setColor(Co