/** 此时 获取控件的 宽高 onSizeChanged 在ondraw之前调用 一般 onSizeChanged调用之后可以认为 (在非onDraw中)控件显示了 */ @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); Log.i("显示控件前设置变量代码执行顺序", "onSizeChanged(int w, int h, int oldw, int oldh)"); width = getWidth(); height = getHeight(); just = width > height ? height : width; maxb = width < height ? height : width; centX = width * 1f / 2; centY = height * 1f / 2; // 防止 突出扇形突出过大 // pointPieOut = just/2-padings; pointPieOut = pointPieOut > padings ? padings : pointPieOut; // 提示线突出饼图至少20 根据外圆的大小可调饼图的半径 if (padings - lpading < TsOut) { padings = (int) (lpading - TsOut); // lpading = padings - TsOut; } pieRadius = just / 2 - padings; // 初始化一些画笔设置 可以外部改变的变量的初始化不要放在构造函数中 // 设置间隔画笔风格 paintInter.setStyle(Style.STROKE); paintInter.setColor(pieInterColor); // 画笔的宽度怎么画 与画笔宽度为0 相比 就是在画笔宽度为0的基础上左右各加粗宽度的一半 paintInter.setStrokeWidth(pieInterWidth); // 当背景为透明的时候 获取布局的背景色 if (Integer.MAX_VALUE == backColor) { backColor = getBackColor(); // ondraw也无法拿到布局中设置的背景色 // backColor = Color.RED; } // ==================================饼图的展现动画=从这里触发====外界无论设置啥变量最后都会走到这====================================== // 内往外 的展现动画 需要在此处出发,,因为这个动画 需要先获取到just if (pieData.size() != 0) { // =================设置完数据后 显示到界面========================== if (!showPieAnimation) { postInvalidate(); return; } aniShowPie(); } }
@Override protected void onDraw(Canvas canvas) { // Log.i("显示控件前设置变量代码执行顺序", "onDraw"); // 无论控件 那边大 都在中间的正方形画饼图 float mWidth = 0; // 宽比高宽多少 float mHeight = 0; // 高比宽高多少 // 画背景 mPaint.setColor(backColor); RectF back = new RectF(0, 0, width, height); canvas.drawRect(back, mPaint); if (width > height) { mWidth = width - height; } else { mHeight = height - width; } // TODO 提示线突出饼图至少20 if (padings - lpading < TsOut) { lpading = padings - TsOut; } RectF oval; if (fillOut) { // 画扇形所需要的 矩形======扇形==从内往外 变大==所用=同时也是最终扇形所用的矩形============ oval = new RectF(centX - fillouting, centY - fillouting, centX + fillouting, centY + fillouting); } else { // ========= 画扇形所需要的 矩形=========== oval = new RectF( padings + mWidth / 2, padings + mHeight / 2, width - padings - mWidth / 2, height - padings - mHeight / 2); } // 画上辅助矩形 // Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); // paint.setStyle(Style.STROKE); // paint.setColor(Color.RED); // canvas.drawRect(oval, paint); // onsizechange已经获取了 。当高大于宽的时候 mwidth=0 // pieRadius = width / 2 - padings - mWidth / 2; // 画饼图扇形========== 间隔 ============= 所需要的 矩形 RectF ovalInter = new RectF( padings - pieInterWidth / 2 + mWidth / 2, padings - pieInterWidth / 2 + mHeight / 2, width - padings + pieInterWidth / 2 - mWidth / 2, height - padings + pieInterWidth / 2 - mHeight / 2); // 画辅助矩形 // paint.setColor(Color.BLUE); // canvas.drawRect(ovalInter, paint); // TODO // 将 提示线的起点 设定到 饼图半径的一半处 if (nRadius == 1) { nRadius = pieRadius / 2; Log.d("提示线起点", "将 提示线的起点 设定到 饼图半径的一半处:" + nRadius); } for (int i = 0; i < pieData.size(); i++) { eachPie pie = pieData.get(i); mPaint.setColor(pie.getPieColor()); // 把每个扇形的起止角度 限定在360之内 方便 float startPie = pie.getStartAngle() + degrees; startPie = startPie > 360 ? startPie - 360 : startPie; startPie = startPie < 0 ? startPie + 360 : startPie; float start = startPie; float end = startPie + pie.getSweepAngle(); end = end > 360 ? end - 360 : end; end = end < 0 ? end + 360 : end; // // 画 特殊角度处 突出的扇形 // if (specialAngle > 0) { // //在这里 判断特殊角的话 需要每次都新建RectF对象 但是不需要多画 一个扇形 // oval = new RectF(padings + mWidth / 2, padings + mHeight / 2, // width - padings - mWidth / 2, height - padings - mHeight / 2); // if (end > specialAngle && start < specialAngle) { // oval = new RectF(padings + mWidth / 2 - pointPieOut, // padings + mHeight / 2 - pointPieOut, width // - padings - mWidth / 2 + pointPieOut, // height - padings - mHeight / 2 + pointPieOut); // } // if (end < start) { // if (end > specialAngle || start < specialAngle) { // oval = new RectF(padings + mWidth / 2 - pointPieOut, // padings + mHeight / 2 - pointPieOut, width // - padings - mWidth / 2 + pointPieOut, // height - padings - mHeight / 2 + pointPieOut); // } // } // } // =============== 画 饼图的扇形===================== canvas.drawArc(oval, startPie, pie.getSweepAngle(), true, mPaint); // 当饼图的间隔线宽度==========不为0 的时候 才画========间隔线==================== if (pieInterWidth != 0) { // TODO float和int数据相比较是否相等 要允许误差存在 if ((fillOut ? Math.abs(fillouting - pieRadius) < 0.1 : true)) { // 当 内往外显示 饼图的时候 变大过程不显示间隔线,饼图完整显示后才画 间隔线 // 在没执行 内往外的动画 时 一直显示 间隔线 // 画间隔 canvas.drawArc(ovalInter, startPie, pie.getSweepAngle(), true, paintInter); // r } } // =====画选中=====的扇形的效果 ========当这个为true的时候 特殊角放大的扇形失效============ if (PieSelector) { specialAngle = 0; if (clickPosition == i) { if ("down".equals(action)) { // 按下时 选择的扇形变小 无法变小 因为我是在原来饼图的上面画了这个特殊的扇形的 drawSpecialPie(canvas, mWidth, mHeight, pie, startPie, -pointPieOut); } else if ("up".equals(action)) { // 提起是 选中的扇形变大 drawSpecialPie(canvas, mWidth, mHeight, pie, startPie, pointPieOut); } } } // = 画 =====特殊角度处===== 突出的扇形 ======当需要的时候new出新的RectF 其实是在饼图上一层多画了一个突出的扇形========= if (specialAngle > 0) { if ((end > specialAngle && start < specialAngle) || (end > specialAngle || start < specialAngle) && (end < start)) { // 设置监听 if (specialPielistener != null) { specialPielistener.onSpecialPie(i, pieData.get(i)); } specialPosition = i; // 画突出扇形 float outORin = pointPieOut; drawSpecialPie(canvas, mWidth, mHeight, pie, startPie, outORin); } } } super.onDraw(canvas); // 先画父类提示线条 //或者放最后 通过修改画提示线的颜色 来让提示线在展示动画之后出现 // ==================================饼图的展现动画=========================================== if (!fillOut && showPieAnimation) { // 不执行fillOut动画 同时 允许出现饼图展现动画 则执行扇形扫描动画 if (!hideAniCircle) { // 扇形动画完后会 变成条线 所以执行完 要去掉这个扇形 // 画最顶层的 白色扇形 360度的 用于展现饼图慢慢展开的效果 mPaint.setColor(backColor); // 画扇形所需要的 矩形 RectF oval4 = new RectF(-maxb, -maxb, maxb + maxb, maxb + maxb); // RectF oval4 = new RectF(mWidth / 2, mHeight / 2, just + mWidth / 2, // just + mHeight / 2); canvas.drawArc(oval4, start4, sweep4, true, mPaint); } } // super.onDraw(canvas);// 通过修改画提示线的颜色 来让提示线在展示动画之后出现 }