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

SetContentView两种用法对比及Android Java画布绘制填充圆技术咨询

嘿,我来帮你把这两个问题唠明白——先搞定Canvas画填充圆的代码,再给你掰扯清楚setContentView两种用法的区别~

一、完善Canvas绘制填充圆形的drawCircles类

你写的类框架已经有了,我帮你补全并优化了关键部分,代码如下:

public class drawCircles extends android.support.v7.widget.AppCompatImageView {
    float x, y;
    Paint paint = new Paint();
    ArrayList<PointF> locations = new ArrayList<PointF>();

    // 代码中直接实例化时用的构造方法
    public drawCircles(Context context) {
        super(context);
        initPaint();
    }

    // 布局XML中引用自定义View时必须的构造方法
    public drawCircles(Context context, AttributeSet attrs) {
        super(context, attrs);
        initPaint();
    }

    public drawCircles(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initPaint();
    }

    // 统一初始化Paint的方法
    private void initPaint() {
        paint.setStyle(Paint.Style.FILL); // 设置为填充模式
        paint.setColor(Color.RED); // 自定义填充颜色,可按需修改
        paint.setAntiAlias(true); // 开启抗锯齿,让圆形边缘更平滑
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
            case MotionEvent.ACTION_MOVE:
                // 获取触摸坐标
                x = event.getX();
                y = event.getY();
                // 保存新的触摸点(注意new一个PointF,避免所有元素指向同一个对象)
                locations.add(new PointF(x, y));
                invalidate(); // 触发View重绘,调用onDraw方法
                return true; // 消费触摸事件,避免传递给父View
            default:
                return super.onTouchEvent(event);
        }
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        // 遍历所有保存的触摸点,绘制填充圆形
        for (PointF point : locations) {
            // 参数依次是:圆心x、圆心y、半径、画笔
            canvas.drawCircle(point.x, point.y, 50, paint);
        }
    }
}

几个关键说明:

  • 补充了带AttributeSet的构造方法:如果要在XML布局里引用这个自定义View,必须要有这些构造方法,否则系统无法实例化它。
  • 统一了Paint的初始化:把画笔的样式、颜色、抗锯齿设置抽成方法,避免重复代码。
  • 优化了触摸点保存:每次添加新的PointF实例,而不是复用同一个对象,否则所有保存的点都会变成最后一次触摸的坐标。
  • 通过invalidate()触发重绘:触摸事件发生后,通知系统重新调用onDraw,把新的圆形画出来。
二、setContentView(类实例)与setContentView(布局XML文件)的区别

这两种方式本质都是给Activity设置内容视图,但适用场景和实现逻辑完全不同:

  • 加载逻辑不同
    • setContentView(R.layout.xxx):系统会通过LayoutInflater解析XML文件,把里面的标签(比如TextView、LinearLayout)转换成对应的View对象,组装成View树后作为Activity的内容视图。简单说就是“从XML生成界面”。
    • setContentView(new drawCircles(this)):直接把你代码创建的自定义View实例作为Activity的根视图,跳过XML解析步骤,属于“用代码直接创建界面”。
  • 适用场景不同
    • XML布局适合复杂多控件组合的界面:比如包含标题栏、列表、按钮、输入框的界面,用XML可以可视化编辑,代码和布局分离,后期维护更方便。
    • 直接传View实例适合高度自定义绘制的场景:像你这个绘图应用,整个界面就是一个自定义View,没有其他多余控件,直接传实例更简洁,也能完全掌控绘制逻辑。
  • 灵活性与控制度不同
    • XML布局的灵活性在于快速调整布局结构,但对View的自定义绘制、触摸逻辑控制有限,需要结合Java/Kotlin代码修改控件属性。
    • 直接传View实例可以完全掌控View的生命周期、绘制流程、触摸事件,适合游戏界面、绘图工具这类需要精细控制UI的场景。
  • 性能差异(可忽略但值得一提)
    • XML布局需要解析文件、反射创建View,会有微小的IO和反射开销,不过普通场景下完全感知不到。
    • 直接传View实例跳过了解析步骤,初始化速度略快,对启动速度敏感的场景(比如闪屏页)可能有帮助,但日常开发不用纠结这点差异。

内容的提问来源于stack exchange,提问作者Chris Aspden

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 10:40:39