You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.09 19:54:03