如何从Activity修改自定义View的Canvas颜色及点击崩溃问题解决
问题核心原因
- 错误缓存了Canvas对象:Android系统仅在
onDraw()方法执行期间提供的Canvas实例有效,你缓存的thecanvas在onDraw执行结束后就会失效,点击按钮调用drawCircle时访问失效的Canvas直接触发崩溃 - 额外性能问题:
onDraw中同时调用postInvalidateDelayed和invalidate会触发无限循环重绘,严重占用系统资源 - 不符合自定义View渲染逻辑:所有绘制操作都应该在
onDraw回调中执行,外部仅需要修改状态变量、触发重绘即可,不能直接调用绘制方法操作画布
解决方案
第一步:修改CustomAnalogClock类
public class CustomAnalogClock extends View { private int height, width = 0; private int padding = 0; private int fontSize = 0; private int numeralSpacing = 0; private int handTruncation, hourHandTruncation = 0; private int radius = 0; private Paint paint; private boolean isInit; private int[] numbers = {1,2,3,4,5,6,7,8,9,10,11,12}; private Rect rect = new Rect(); // 新增:存储外圈颜色的成员变量,默认红色 private int mCircleColor = Color.RED; public CustomAnalogClock(Context context) { super(context); } public CustomAnalogClock(Context context, AttributeSet attrs) { super(context, attrs); } public CustomAnalogClock(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } private void initClock() { height = getHeight(); width = getWidth(); padding = numeralSpacing + 50; fontSize = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 13,getResources().getDisplayMetrics()); int min = Math.min(height, width); radius = min / 2 - padding; handTruncation = min / 20; hourHandTruncation = min / 7; paint = new Paint(); isInit = true; } @Override protected void onDraw(Canvas canvas) { if (!isInit) { initClock(); } canvas.drawColor(Color.BLACK); // 传入当前有效的Canvas绘制外圈 drawCircle(canvas); drawCenter(canvas); drawNumeral(canvas); drawHands(canvas); // 移除多余的invalidate,仅保留延迟刷新即可 postInvalidateDelayed(500); } private void drawHand(Canvas canvas, double loc, boolean isHour) { double angle = Math.PI * loc / 30 - Math.PI / 2; int handRadius = isHour ? radius - handTruncation - hourHandTruncation : radius - handTruncation; canvas.drawLine(width / 2, height / 2, (float) (width / 2 + Math.cos(angle) * handRadius), (float) (height / 2 + Math.sin(angle) * handRadius), paint); } public void drawHands(Canvas canvas) { Calendar c = Calendar.getInstance(); float hour = c.get(Calendar.HOUR_OF_DAY); hour = hour > 12 ? hour - 12 : hour; drawHand(canvas, (hour + c.get(Calendar.MINUTE) / 60) * 5f, true); drawHand(canvas, c.get(Calendar.MINUTE), false); drawHand(canvas, c.get(Calendar.SECOND), false); } private void drawNumeral(Canvas canvas) { paint.setTextSize(fontSize); for (int number : numbers) { String tmp = String.valueOf(number); paint.getTextBounds(tmp, 0, tmp.length(), rect); double angle = Math.PI / 6 * (number - 3); int x = (int) (width / 2 + Math.cos(angle) * radius - rect.width() / 2); int y = (int) (height / 2 + Math.sin(angle) * radius + rect.height() / 2); canvas.drawText(tmp, x, y, paint); } } private void drawCenter(Canvas canvas) { paint.setStyle(Paint.Style.FILL); canvas.drawCircle(width / 2, height / 2, 12, paint); } // 修改:接收当前有效的Canvas作为参数,使用成员变量的颜色绘制 private void drawCircle(Canvas canvas) { paint.reset(); paint.setColor(mCircleColor); paint.setStrokeWidth(5); paint.setStyle(Paint.Style.STROKE); paint.setAntiAlias(true); canvas.drawCircle(width / 2, height / 2, radius + padding - 10, paint); } // 新增:对外暴露的修改外圈颜色方法 public void setCircleColor(int color) { this.mCircleColor = color; // 触发View重绘,会自动调用onDraw方法使用新颜色绘制 invalidate(); } }
第二步:修改按钮点击逻辑
change_canvas_Color.setOnClickListener { customAnalogClockCarpte.setCircleColor(Color.GREEN) }
内容的提问来源于stack exchange,提问作者Kaita John
相关产品推荐
相关产品推荐

