自定义控件最重要的是需要重写三个构造方法,分别是一个参数、连个参数以及三个参数的,这是最重要的三个。接下来,想要自定义显示饼图就要重写onMeasure以及onDraw方法。
onMeasure方法的主要作用就是重新计算控件的宽高并设置,因为要显示的是饼状图,而饼状图是圆形的相对于控件来说饼状图就是正方形的,所以就要通过这个方法来进行限制,使控件的宽高保持所设置的最小的宽高。
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int height = getDefaultSize(getSuggestedMinimumHeight(),
heightMeasureSpec);
int width = getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec);
minMargin = Math.min(width, height);//取边框的最小值来显示图表
setMeasuredDimension(minMargin, minMargin);
rect = new RectF(0,0,minMargin,minMargin);//按照所设置的宽高中的最小值来设置范围
}
onDraw方法的主要作用就是渲染绘制视图,也就是人们肉眼所看到的部分的效果了,其实画饼状图追主要用到的就是画布的drawArc方法,他的主要作用就是花扇形图;
@Override
protected void onDraw(Canvas canvas) {
if(backgroundBitmap == null) {
//显示是百分比饼图,动画以及非动画
showPercentCircle(canvas);
}else {
canvas.drawBitmap(getCroppedRoundBitmap(backgroundBitmap,getWidth()/2),0,0,null);
}
//画空心圆
if(strokeWidth != null) {
Paint paintStroke = new Paint();
paintStroke.setColor(Color.WHITE);
canvas.drawCircle(getWidth() / 2 , getHeight() / 2 ,strokeWidth * minMargin, paintStroke);
}
//绘制除百分比以外文字
if(showText != null){
if(showTextCenterX == null || showTextBaselineY == null) {
showTextPaint.setTextSize(showTextSize);
showTextPaint.setColor(showTextColor);
setTextLocation();
}
if(showTextCenterX != null && showTextBaselineY != null) {
showTextPaint.setTextSize(showTextSize);
showTextPaint.setColor(showTextColor);
canvas.drawText(showText, showTextCenterX, showTextBaselineY, showTextPaint);
}
}
}
接下来就是各个数据的初始化方法了:
/**
* 设置要显示的内容,主要是,名称颜色以及百分比,此时的百分比是10的整数倍形式
* @param list
*/
public void setShowList(List
ondraw方法内部的调用方法是:
/**
* //显示是百分比饼图,动画以及非动画
* @param canvas
*/
private void showPercentCircle(Canvas canvas){
if(isShowAnim){
for(int i = 0 ; i < list.size() ; i++){
paint.setColor((int) list.get(i).get(KEY_COLOR)); //设置画笔颜色
int percent = 0;
if( i == 0) {//0的时候单独设置,因为需要从0开始
canvas.drawArc(rect, 0, (float) (rotationAngle * (int) list.get(i).get(KEY_PERCENT) * 1.0 /100), true, paint);
}else {
for (int j = 0; j < i; j++) {
percent += (int) list.get(j).get(KEY_PERCENT);
}
percent = (int) (percent * 1.0 / 100 * maxRotationAngle);//计算已经显示过的百分比所旋转的角度
canvas.drawArc(rect,percent,
(float) (rotationAngle * (int) list.get(i).get(KEY_PERCENT) * 1.0 /100 + 1)
,true,paint);//非零状态下的动画绘制需要从该条的起点开始绘制,每次绘制需要加1,防止四舍五入产生误差
}
}
}else {
oldRotationAngle = 0;
for(int i = 0 ; i < (list != null ? list.size() : 0) ; i++){//(list != null ? list.size() : 0)
paint.setColor((int)list.get(i).get(KEY_COLOR)); //设置画笔颜色
rotationAngle = (int) ((int)list.get(i).get(KEY_PERCENT) * 1.0 / 100 * maxRotationAngle);
canvas.drawArc(rect,oldRotationAngle, rotationAngle, true, paint);
oldRotationAngle = oldRotationAngle + rotationAngle;
}
}
if(rotationAngle == maxRotationAngle || !isShowAnim){
for(int j = 0 ; j < (list != null ? list.size() : 0) ; j++){
int percent = 0;
for (int k = 0; k < j; k++) {
percent += (int) list.get(k).get(KEY_PERCENT);
}
percent = (int) (percent * 1.0 / 100 * maxRotationAngle);
paint.setColor(Color.GREEN); //设置画笔颜色
if(minMargin != 0 ) {
xChartCalcPercentText = new XChartCalc();
xChartCalcPercentText.CalcArcEndPointXY(minMargin / 2 , minMargin / 2);
canvas.drawText((String) list.get(j).get(KEY_NAME)
,xChartCalcPercentText.setCirAngle(minMargin / 2 - minMargin / 6,percent + (float) ((int) list.get(j).get(KEY_PERCENT) * 0.5 /100) * maxRotationAngle)
.getPosX()
,xChartCalcPercentText.setCirAngle(minMargin / 2 - minMargin / 6,percent + (float) ((int) list.get(j).get(KEY_PERCENT) * 0.5 /100) * maxRotationAngle)
.getPosY()
,paint);//文字在扇形的中间线上的某一点显示
}
}
}
}
/**
* 定位文本绘制的位置
*/
private void setTextLocation() {
fm = showTextPaint.getFontMetrics();
//文本的宽度
float textWidth = showTextPaint.measureText(showText);
float textHeight = fm.descent - fm.ascent;
float textCenterVerticalBaselineY = viewHeight / 2 - fm.descent + (fm.descent - fm.ascent) / 2;
switch (showTextAlign) {
case TEXT_ALIGN_CENTER://居中
showTextCenterX = (float)viewWidth / 2;
showTextBaselineY = textCenterVerticalBaselineY;
break;
case TEXT_ALIGN_LEFT_CENTER://居中靠最左
showTextCenterX = textWidth / 2;
showTextBaselineY = textCenterVerticalBaselineY;
break;
case TEXT_ALIGN_RIGHT_CENTER://居中靠最右
showTextCenterX = viewWidth - textWidth / 2;
showTextBaselineY = textCenterVerticalBaselineY;
break;
case TEXT_ALIGN_CENTER_HORIZONTAL_BOTTOM://居中靠最下
showTextCenterX = Float.valueOf(viewWidth / 2);
showTextBaselineY = viewHeight - fm.bottom;
break;
case TEXT_ALIGN_CENTER_HORIZONTAL_TOP://居中靠最上
showTextCenterX = Float.valueOf(viewWidth / 2);
showTextBaselineY = -fm.ascent;
break;
case TEXT_ALIGN_LEFT_TOP://左上
showTextCenterX = textWidth / 2;
showTextBaselineY = -fm.ascent;
break;
case TEXT_ALIGN_LEFT_BOTTOM://左下
showTextCenterX = textWidth / 2;//
showTextBaselineY = viewHeight - fm.bottom;
break;
case TEXT_ALIGN_RIGHT_TOP://右上
showTextCenterX = viewWidth - textWidth / 2;
showTextBaselineY = -fm.ascent;
break;
case TEXT_ALIGN_RIGHT_BOTTOM://右下
showTextCenterX = viewWidth - textWidth / 2;
showTextBaselineY = viewHeight - fm.bottom;
break;
case TEXT_ALIGN_CENTER_TOP://居中靠上
showTextCenterX = (float)viewWidth / 2;
showTextBaselineY = textCenterVerticalBaselineY - textHeight / 2;
break;
case TEXT_ALIGN_CENTER_BOTTOM:/** 居中靠下显示 */
showTextCenterX = (float)viewWidth / 2;
showTextBaselineY = textCenterVerticalBaselineY + textHeight / 2;
break;
case TEXT_ALIGN_CENTER_LEFT:/** 居中靠左显示 */
showTextCenterX = (float)viewWidth / 2 - textWidth / 2 ;
showTextBaselineY = textCenterVerticalBaselineY;
break;
case TEXT_ALIGN_CENTER_RIGHT:/** 居中靠右显示 */
showTextCenterX = (float)viewWidth / 2 + textWidth / 2 ;
showTextBaselineY = textCenterVerticalBaselineY;
break;
case TEXT_ALIGN_CENTER_LEFT_TOP:/** 居中靠左上显示 */
showTextCenterX = (float)viewWidth / 2 - textWidth / 2 ;
showTextBaselineY = textCenterVerticalBaselineY - textHeight / 2 ;
break;
case TEXT_ALIGN_CENTER_LEFT_BOTTOM:/** 居中靠左下显示 */
showTextCenterX = (float)viewWidth / 2 - textWidth / 2 ;
showTextBaselineY = textCenterVerticalBaselineY + textHeight / 2 ;
break;
case TEXT_ALIGN_CENTER_RIGHT_TOP:/** 居中靠右上显示 */
showTextCenterX = (float)viewWidth / 2 + textWidth / 2 ;
showTextBaselineY = textCenterVerticalBaselineY - textHeight / 2 ;
break;
case TEXT_ALIGN_CENTER_RIGHT_BOTTOM:/** 居中靠右下显示 */
showTextCenterX = (float)viewWidth / 2 + textWidth / 2 ;
showTextBaselineY = textCenterVerticalBaselineY + textHeight / 2 ;
break;
}
}
这些是最初的的一些基础代码,其中空心圆的实现是在实心圆的外层添加一个小于实心圆半径的白色或者说是背景色的实心圆,这样在最终绘制出来的图片的效果上就会是显示出空心圆。
动画的显示是使用的Animation的计时器,因为想要实现动画的效果必须要开子线程,但是所开的子线程销毁又是一个问题,所以使用动画来计时,在计时之后他会自动将自己本身的线程销毁,而之所以在计时的时候对图像进行绘制是使用了Animation的applyTransformation方法,他会在动画显示的时候进行不定时的回调,其中他的参数interpolatedTime是表示动画已经执行的时间的百分比,其范围是“0-1”,每次回调该方法的时候都使用view.postInvalidate();方法来对视图进行重绘:
@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
super.applyTransformation(interpolatedTime, t);
view.postInvalidate();
setListener.percent(interpolatedTime);
}
在使用这个控件的时候需要向该控件传递百分比等数据,然后在调用控件的公开方法传递,其格式如下:
list = new ArrayList<>();
Map map = new HashMap<>();
map.put(PieChartView.KEY_NAME,"red");
map.put(PieChartView.KEY_PERCENT,40);
map.put(PieChartView.KEY_COLOR, Color.RED);
list.add(map);
map = new HashMap<>();
map.put(PieChartView.KEY_NAME,"gray");
map.put(PieChartView.KEY_PERCENT,30);
map.put(PieChartView.KEY_COLOR, Color.GRAY);
list.add(map);
map = new HashMap<>();
map.put(PieChartView.KEY_NAME,"blue");
map.put(PieChartView.KEY_PERCENT,10);
map.put(PieChartView.KEY_COLOR, Color.BLUE);
list.add(map);
map = new HashMap<>();
map.put(PieChartView.KEY_NAME,"black");
map.put(PieChartView.KEY_PERCENT,20);
map.put(PieChartView.KEY_COLOR, Color.BLACK);
list.add(map);
源码下载链接:http://download.csdn.net/detail/cmwly/9591797