在 Android 中,自定义 View 的绘制流程

目录

[1. 测量阶段 (onMeasure())](#1. 测量阶段 (onMeasure()))

[2. 布局阶段 (onLayout())](#2. 布局阶段 (onLayout()))

[3. 绘制阶段 (onDraw())](#3. 绘制阶段 (onDraw()))

总体绘制流程

注意事项

示例总结

参考资料


在 Android 中,自定义 View 的绘制流程主要包括测量布局绘制 三个关键步骤。具体来说,自定义 View 的绘制涉及重写系统的 onMeasure()onLayout()onDraw() 方法。下面详细介绍这个流程:

1. 测量阶段 (onMeasure())

onMeasure() 方法用于确定 View 的尺寸。系统会调用该方法来让自定义 View 计算其宽度和高度。你可以根据父布局给定的测量模式和尺寸对 View 进行自适应处理。

  • 系统提供了三种测量模式:
    1. EXACTLY: 父布局强制给定的大小。自定义 View 必须使用该大小。
    2. AT_MOST: 父布局允许的最大尺寸。View 可以小于或等于这个尺寸。
    3. UNSPECIFIED: 父布局对 View 的尺寸没有任何限制。

示例:

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    int widthMode = MeasureSpec.getMode(widthMeasureSpec);
    int heightMode = MeasureSpec.getMode(heightMeasureSpec);
    
    int widthSize = MeasureSpec.getSize(widthMeasureSpec);
    int heightSize = MeasureSpec.getSize(heightMeasureSpec);
    
    // 计算出自定义 View 的大小
    int width = calculateWidth(widthMode, widthSize);
    int height = calculateHeight(heightMode, heightSize);
    
    // 调用 setMeasuredDimension 设置测量的宽高
    setMeasuredDimension(width, height);
}

2. 布局阶段 (onLayout())

onLayout() 方法用于安排子 View 的位置。自定义 View 本身没有子 View 时,通常不需要重写此方法。只有自定义 ViewGroup(包含子 View 的容器)时才需要重写。

onLayout() 中,确定每个子 View 的摆放位置,可以通过 child.layout(left, top, right, bottom) 来安排子 View 的布局。

示例:

@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
    // 如果有子 View,调用每个子 View 的 layout() 方法设置它们的位置
    int childCount = getChildCount();
    for (int i = 0; i < childCount; i++) {
        View child = getChildAt(i);
        child.layout(left, top, right, bottom); // 设置子 View 的位置
    }
}

3. 绘制阶段 (onDraw())

onDraw() 方法用于执行实际的绘制操作。开发者可以通过重写该方法来定义自定义 View 的外观。在 onDraw() 中,使用 Canvas 对象绘制图形、文本、图片等。

onDraw() 方法中:

  • 使用 Canvas 提供的方法来绘制图形(如 drawRect()drawCircle() 等)。
  • Paint 对象用于设置绘制样式,如颜色、线条粗细、字体等。

示例:

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    
    // 设置画笔
    Paint paint = new Paint();
    paint.setColor(Color.BLUE);
    paint.setStyle(Paint.Style.FILL);
    
    // 画一个圆
    canvas.drawCircle(getWidth() / 2, getHeight() / 2, Math.min(getWidth(), getHeight()) / 2, paint);
}

总体绘制流程

  1. Measure : 首先调用 onMeasure() 方法,测量 View 的尺寸并传递给 View 的父布局。父布局基于测量结果决定如何分配空间给子 View。

  2. Layout : 在测量结束后,调用 onLayout() 方法对 View 进行布局。对于自定义 ViewGroup,父布局会传递给子 View 的具体位置坐标。

  3. Draw : 布局完成后,系统会调用 onDraw() 方法。onDraw() 主要负责绘制内容,例如图形、文字等。绘制顺序为:

  • 背景
  • 自身内容(如文字、图形)
  • 子 View
  • 滑动条等装饰

注意事项

  • 在执行 onDraw() 时,确保绘制效率。如果绘制操作过于复杂,可能会导致卡顿,应尽量避免在 onDraw() 中进行复杂的计算。
  • 重写 onMeasure() 时,必须调用 setMeasuredDimension() 来设置 View 的宽高,否则系统将无法正确布局该 View。
  • 需要使用 invalidate() 来触发重新绘制操作。

示例总结

public class CustomView extends View {

    public CustomView(Context context) {
        super(context);
    }

    public CustomView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int width = MeasureSpec.getSize(widthMeasureSpec);
        int height = MeasureSpec.getSize(heightMeasureSpec);
        setMeasuredDimension(width, height);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        Paint paint = new Paint();
        paint.setColor(Color.RED);
        paint.setStyle(Paint.Style.FILL);
        canvas.drawCircle(getWidth() / 2, getHeight() / 2, 100, paint);
    }
}

参考资料

相关推荐
TT哇5 分钟前
*【每日一题 提高题】[蓝桥杯 2022 国 A] 选素数
java·算法·蓝桥杯
火烧屁屁啦27 分钟前
【JavaEE进阶】初始Spring Web MVC
java·spring·java-ee
飞飞-躺着更舒服31 分钟前
【QT】实现电子飞行显示器(改进版)
开发语言·qt
w_312345441 分钟前
自定义一个maven骨架 | 最佳实践
java·maven·intellij-idea
岁岁岁平安43 分钟前
spring学习(spring-DI(字符串或对象引用注入、集合注入)(XML配置))
java·学习·spring·依赖注入·集合注入·基本数据类型注入·引用数据类型注入
武昌库里写JAVA1 小时前
Java成长之路(一)--SpringBoot基础学习--SpringBoot代码测试
java·开发语言·spring boot·学习·课程设计
Q_19284999061 小时前
基于Spring Boot的九州美食城商户一体化系统
java·spring boot·后端
张国荣家的弟弟1 小时前
【Yonghong 企业日常问题 06】上传的文件不在白名单,修改allow.jar.digest属性添加允许上传的文件SH256值?
java·jar·bi
ZSYP-S1 小时前
Day 15:Spring 框架基础
java·开发语言·数据结构·后端·spring
yuanbenshidiaos1 小时前
c++------------------函数
开发语言·c++