android自定义View的核心流程和关键方法

Android 自定义 View 的核心流程主要围绕 测量(Measure)布局(Layout)绘制(Draw) 三大阶段,对应的关键方法是 onMeasure()onLayout()onDraw()。如果是自定义 ViewGroup,还需要额外处理子 View 的测量与布局。以下是详细说明:


一、测量阶段 ------ 确定 View 的宽高

核心方法: onMeasure(int widthMeasureSpec, int heightMeasureSpec)

  • MeasureSpec 由父 View 传入,包含 模式(Mode)尺寸(Size)
    • EXACTLY:确定大小(如 match_parent 或具体 dp 值)。
    • AT_MOST:最大不超过某值(如 wrap_content)。
    • UNSPECIFIED:无限制(较少使用,如 ScrollView 内部)。
  • 必须调用 setMeasuredDimension(width, height) 保存测量结果。
  • 注意 :若为 wrap_content 需要自行计算内容所需尺寸(否则可能占据全父容器)。

辅助方法:

  • resolveSize(int desiredSize, int measureSpec):根据 MeasureSpec 计算合适的尺寸。

二、布局阶段 ------ 确定 View 的位置(仅 ViewGroup 必须重写)

核心方法: onLayout(boolean changed, int left, int top, int right, int bottom)

  • 对于普通 View(非容器),通常不需要重写(位置由父 View 决定)。
  • 对于 ViewGroup ,必须重写该方法,遍历所有子 View 并调用子 View 的 layout(l, t, r, b) 来设定它们的位置。
  • 参数 changed 表示 View 的尺寸或位置是否改变。

相关方法:

  • requestLayout():触发重新测量和布局。

三、绘制阶段 ------ 显示内容

核心方法: onDraw(Canvas canvas)

  • 使用 CanvasPaint 绘制图形、文字、图片等。
  • 避免在 onDraw 中创建对象(防止频繁 GC)。
  • 通过 invalidate() 触发重绘(可在任意线程调用,内部会 post 到 UI 线程)。

绘制层级:

ViewGroup 默认会先绘制自身背景(调用 onDraw),再调用 dispatchDraw(Canvas) 绘制子 View。若需要自定义绘制顺序,可重写 dispatchDraw()


四、其他关键方法

方法 作用 调用时机
构造方法 解析自定义属性(TypedArray),初始化 Paint 等对象 代码或 XML 创建 View 时
onSizeChanged(int w, int h, int oldw, int oldh) 监测量尺寸变化,常用于初始化与宽高相关的数据(如 Bitmap、路径) 第一次测量或尺寸改变后
onAttachedToWindow() / onDetachedFromWindow() 处理窗口附着与分离时的资源操作(如注册/注销监听) View 添加到/移出窗口时
onMeasure 中的 getSuggestedMinimumWidth() 获取 View 建议的最小宽度(由背景或 android:minWidth 决定) 测量阶段内部调用
invalidate() 标记 View 为"脏",触发重绘(仅调用 onDraw,不重新测量布局) UI 数据改变需要刷新显示时
requestLayout() 标记 View 树需要重新测量和布局(会依次调用 onMeasureonLayout 宽高或位置数据改变时

五、自定义属性(可选但常用)

  1. res/values/attrs.xml 中声明 <declare-styleable>
  2. 构造方法中通过 context.obtainStyledAttributes() 获取 TypedArray,解析自定义属性值。
  3. 记得 recycle()

六、典型流程时序(以 ViewGroup 为例)

sql 复制代码
构造方法 → onMeasure(测量自身及子View)→ onLayout(摆放子View)→ onDraw(绘制内容)

若触发 invalidate():仅重新执行 onDraw

若触发 requestLayout():重新执行 onMeasureonLayoutonDraw


七、注意事项

  1. 性能 :避免在 onDraw 中分配对象;减少 invalidate 区域(invalidate(Rect))。
  2. wrap_content :自定义 View 必须自己处理,否则效果等同 match_parent
  3. Padding :如果自定义 View 支持 padding,需要在 onDraw 中主动偏移绘制区域,或在 onMeasure 中减去 padding
  4. 线程 :UI 操作(除 invalidate 外)必须在主线程。
  5. 触摸事件 (扩展):若需要交互,重写 onTouchEventdispatchTouchEvent

总结

类型 必须重写的方法 通常重写的方法
自定义 View onMeasureonDraw 构造方法、onSizeChanged
自定义 ViewGroup onMeasureonLayout onDraw(若需要绘制背景)、dispatchDraw

理解这三步流程和关键方法的调用链,即可灵活实现各种自定义控件。

相关推荐
綝~1 天前
爬虫数据采集工程师岗位面试题
爬虫·面试·请求
乐观的山里娃1 天前
【反八股 01】HashMap 的设计参数是怎么来的
面试
嵌入式ZYXC1 天前
第3篇:《面试题:I2C为什么要加上拉电阻?阻值怎么选?》
stm32·单片机·嵌入式硬件·面试·职场和发展
sbjdhjd1 天前
面试(5)| 3.5 小时面试复盘第五弹:加班出差 + 客户响应 + 压力面全拆解
经验分享·程序人生·面试·职场和发展·开源·跳槽·求职招聘
AI人工智能+电脑小能手1 天前
【大白话说Java面试题 第102题】【并发篇】第2题:volatile 能否保证线程安全?
java·安全·面试
Patrick_Wilson1 天前
Git Worktree 原理详解:从 objects / refs 看懂多分支并行与多 Agent 协作
git·面试·ai编程
Moment1 天前
我做了一套前端也能学懂的 AI Agent 系列,从 Prompt 一路讲到多 Agent 😍😍😍
前端·后端·面试
中小企业实战军师刘孙亮1 天前
快消纺织五金怎么融合?三大业态协同发展战略思路-佛山鼎策创局破局增长咨询
学习·面试·创业创新·制造·学习方法
不懂数据的小白1 天前
面试题一:【一】指标体系的搭建(基石)
面试
sbjdhjd1 天前
面试题完结 | 投票题 + 到岗时间 + 压力缓解
经验分享·笔记·面试·职场和发展·开源·求职招聘·印象笔记