乐闻世界logo
搜索文章和话题

Android中View的绘制流程是怎样的?

3月7日 12:12

View的绘制流程是Android UI系统的核心,理解绘制机制对于自定义View和性能优化至关重要。

View绘制的三个阶段

View的绘制流程遵循Measure → Layout → Draw三个阶段:

shell
View绘制流程: measure() → onMeasure() → 测量View宽高 layout() → onLayout() → 确定View位置 draw() → onDraw() → 绘制View内容

第一阶段:Measure(测量)

测量目的

确定View的宽度和高度(measuredWidth/measuredHeight)。

MeasureSpec

MeasureSpec是父View对子View的尺寸要求,由模式尺寸组成:

模式含义
EXACTLY0x40000000精确值,如match_parent或具体数值
AT_MOST0x80000000最大值,如wrap_content
UNSPECIFIED0x00000000无限制,如ScrollView中的子View

测量流程

java
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int widthMode = MeasureSpec.getMode(widthMeasureSpec); int widthSize = MeasureSpec.getSize(widthMeasureSpec); // 根据模式计算实际尺寸 int width = calculateWidth(widthMode, widthSize); int height = calculateHeight(heightMeasureSpec); setMeasuredDimension(width, height); }

第二阶段:Layout(布局)

布局目的

确定View在父容器中的位置(left, top, right, bottom)。

布局流程

java
@Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { // 遍历子View,确定每个子View的位置 for (int i = 0; i < getChildCount(); i++) { View child = getChildAt(i); child.layout(childLeft, childTop, childRight, childBottom); } }

第三阶段:Draw(绘制)

绘制步骤

draw()方法包含6个步骤:

java
public void draw(Canvas canvas) { // 1. 绘制背景 drawBackground(canvas); // 2. 保存画布状态 saveCount = canvas.getSaveCount(); // 3. 绘制内容(子类实现) onDraw(canvas); // 4. 绘制子View dispatchDraw(canvas); // 5. 绘制装饰(如滚动条) onDrawForeground(canvas); // 6. 恢复画布状态 canvas.restoreToCount(saveCount); }

ViewGroup的绘制特点

ViewGroup继承自View,但增加了子View管理:

  1. 测量阶段:遍历测量所有子View
  2. 布局阶段:确定子View的位置
  3. 绘制阶段:dispatchDraw()绘制所有子View

绘制优化技巧

1. 减少重绘

java
// 使用invalidate(Rect)局部重绘 invalidate(0, 0, 100, 100); // 使用ViewStub延迟加载 <ViewStub android:id="@+id/stub" android:layout="@layout/view" />

2. 避免过度绘制

  • 移除不必要的背景
  • 使用clipRect减少绘制区域
  • 使用GPU Overdraw调试工具检测

3. 使用硬件加速

xml
<application android:hardwareAccelerated="true">

自定义View要点

java
public class CustomView extends View { @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); // 处理wrap_content if (MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.AT_MOST) { setMeasuredDimension(defaultWidth, defaultHeight); } } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); // 绘制自定义内容 canvas.drawCircle(cx, cy, radius, paint); } }

面试要点

  • 理解MeasureSpec的三种模式
  • 掌握requestLayout()和invalidate()的区别
  • 了解绘制流程的触发时机
  • 掌握自定义View的基本步骤
  • 理解硬件加速和软件绘制的区别
标签:Android