本文主要是介绍自定义View实战之饼状图效果实现,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
效果图预览
1. 分析
1. 饼状图这个首先需要确定几块饼,确定每一块饼需要绘制的角度
2. 根据饼的范围计算百分比的坐标位置
3. 动画处理
4. 中间白色圆和文字的绘制
2. 实现原理
1. 绘制各个饼,可以有两种实现方式 一种通过canvas.drawArc然后中间部分用白色圆给盖住,
另一种方式是Path.arcTo然后用path.op方法取交集
2. 绘制中间文字和白色的圆 通过canvas.drawCircle和canvas.drawText
3.动画处理 计算每一个饼扫描过的角度 计算每一块绘制的角度
3. 初始化一些东西 初始化一般我放在onSizeChanged方法中
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {super.onSizeChanged(w, h, oldw, oldh);mCenterX = w / 2;mCenterY = h / 2;mInRadius = dp2px(60);mOutRadius = dp2px(120);// setProgressAnimation(DURATION);
}
4. 绘制中间白色圆和中心文字
//画中间白色的圆
private void drawWhiteCircle(Canvas canvas) {canvas.drawCircle(0,0,mInRadius,mWhiteCirclePaint);
}//画中间饼状图文字
private void drawText(Canvas canvas) {String text = "饼状图";//设置文字水平居中mTextPaint.setTextAlign(Paint.Align.CENTER);//测量文字的宽高 要使文字竖直方向也居中mTextPaint.getTextBounds(text,0,text.length(), mTextRect);int height = mTextRect.height();canvas.drawText(text,0,0+height / 2,mTextPaint);
}
5. 画饼状扇形图 这里我为了简单平分了5份饼
- canvas.save()和canvas.restore()是为了保证当前画布操作不会影响之前或者之后的操作,需要注意的是一般是存对出现,不然可能会抛异常
- mPieChartNum:你要等分的饼的数量 这里我就为了简单等分了5份
- mDrawAngle:每一个饼状图扫描的角度 比如均分5个饼的话 mDrawAngle = 360 / 5 = 72度
- //分别是计算x,y方向的坐标值
mOutRadius*(float) Math.cos(Math.toRadians(mStartAngle))
mOutRadius*(float) Math.sin(Math.toRadians(mStartAngle))
mOutPath.arcTo 添加圆环 - 取圆和圆环的交集
// op(a,b,Path.Op.REVERSE_DIFFERENCE) b-a的交集
mPath.op(mInPath,mOutPath, Path.Op.REVERSE_DIFFERENCE)
//画饼状扇形
private void drawPieChart(Canvas canvas) {canvas.save();mInPath.reset();mOutRectF.set(-mOutRadius, -mOutRadius, mOutRadius, mOutRadius);mInPath.addCircle(0,0,mInRadius, Path.Direction.CW);for (int i = 0; i < mPieChartNum; i++) {mStartAngle = (i == 0) ? 0 : mStartAngle + mScaleAngle;if (Math.min(mDrawAngle, mAnimatedValue - mStartAngle) >= 0) {float drawAngle = Math.min(mDrawAngle, mAnimatedValue - mStartAngle);mOutPaint.setColor(mColors[i]);mOutPath.lineTo(mOutRadius*(float) Math.cos(Math.toRadians(mStartAngle)),mOutRadius*(float) Math.sin(Math.toRadians(mStartAngle)));mOutPath.arcTo(mOutRectF, mStartAngle, drawAngle);// op(a,b,Path.Op.REVERSE_DIFFERENCE) b-a的交集mPath.op(mInPath,mOutPath, Path.Op.REVERSE_DIFFERENCE);canvas.drawPath(mPath,mOutPaint);//画透明度圆环drawInRing(canvas,mStartAngle,drawAngle);//画完一段圆弧再画百分比文字if(drawAngle % mDrawAngle== 0) {drawPercentText(canvas, mStartAngle);}}mPath.reset();mOutPath.reset();}canvas.restore();
}//画百分比文字
private void drawPercentText(Canvas canvas,float startAngle) {float angle = mDrawAngle / 2 + startAngle;//计算x,y的时候其实并不需要在不同象限单独计算 比如说 cos0 = 1 -cos(180-180) = cos 180 = -1float x = (float) (0.75 * mOutRadius * Math.cos(Math.toRadians(angle))) ;float y = (float) (0.75 * mOutRadius * Math.sin(Math.toRadians(angle))) ;DecimalFormat df = new DecimalFormat("0");String format = df.format(100 * 1.0f / mPieChartNum) + "%";mTextPaint.getTextBounds(format,0,format.length(),mPercentRect);canvas.drawText(format,x,y + mPercentRect.height() / 2,mTextPaint);
}
6. 动画处理
//设置进度条动画
public void setProgressAnimation(long duration) {if(mProgressAnimator != null && mProgressAnimator.isRunning()){mProgressAnimator.cancel();mProgressAnimator.start();}else {mProgressAnimator = ValueAnimator.ofFloat(0, 360).setDuration(duration);mProgressAnimator.setInterpolator(new AccelerateInterpolator());mProgressAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(ValueAnimator animation) {/**每次要绘制的圆弧角度**/mAnimatedValue = (float) animation.getAnimatedValue();invalidate();}});mProgressAnimator.start();}
}
7. 项目源代码下载
后面统一提供代码下载地址
8. 联系方式
QQ:1509815887
这篇关于自定义View实战之饼状图效果实现的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!