The View drawing process is the core of Android UI system. Understanding the drawing mechanism is crucial for custom Views and performance optimization.
Three Stages of View Drawing
View drawing follows Measure → Layout → Draw three stages:
shellView drawing flow: measure() → onMeasure() → Measure View width/height ↓ layout() → onLayout() → Determine View position ↓ draw() → onDraw() → Draw View content
Stage 1: Measure
Purpose
Determine View's width and height (measuredWidth/measuredHeight).
MeasureSpec
MeasureSpec is the parent View's size requirement for child View, composed of mode and size:
| Mode | Value | Meaning |
|---|---|---|
| EXACTLY | 0x40000000 | Exact value, like match_parent or specific value |
| AT_MOST | 0x80000000 | Maximum value, like wrap_content |
| UNSPECIFIED | 0x00000000 | No limit, like child in ScrollView |
Measurement Flow
java@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int widthMode = MeasureSpec.getMode(widthMeasureSpec); int widthSize = MeasureSpec.getSize(widthMeasureSpec); // Calculate actual size based on mode int width = calculateWidth(widthMode, widthSize); int height = calculateHeight(heightMeasureSpec); setMeasuredDimension(width, height); }
Stage 2: Layout
Purpose
Determine View's position in parent container (left, top, right, bottom).
Layout Flow
java@Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { // Iterate child Views, determine each child's position for (int i = 0; i < getChildCount(); i++) { View child = getChildAt(i); child.layout(childLeft, childTop, childRight, childBottom); } }
Stage 3: Draw
Drawing Steps
draw() method contains 6 steps:
javapublic void draw(Canvas canvas) { // 1. Draw background drawBackground(canvas); // 2. Save canvas state saveCount = canvas.getSaveCount(); // 3. Draw content (implemented by subclass) onDraw(canvas); // 4. Draw child Views dispatchDraw(canvas); // 5. Draw decorations (like scrollbars) onDrawForeground(canvas); // 6. Restore canvas state canvas.restoreToCount(saveCount); }
ViewGroup Drawing Characteristics
ViewGroup extends View but adds child View management:
- Measure Stage: Iterate and measure all child Views
- Layout Stage: Determine child View positions
- Draw Stage: dispatchDraw() draws all child Views
Drawing Optimization Tips
1. Reduce Redraws
java// Use invalidate(Rect) for partial redraw invalidate(0, 0, 100, 100); // Use ViewStub for lazy loading <ViewStub android:id="@+id/stub" android:layout="@layout/view" />
2. Avoid Overdraw
- Remove unnecessary backgrounds
- Use clipRect to reduce drawing area
- Use GPU Overdraw debug tool
3. Use Hardware Acceleration
xml<application android:hardwareAccelerated="true">
Custom View Essentials
javapublic class CustomView extends View { @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); // Handle wrap_content if (MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.AT_MOST) { setMeasuredDimension(defaultWidth, defaultHeight); } } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); // Draw custom content canvas.drawCircle(cx, cy, radius, paint); } }
Key Points
- Understand three modes of MeasureSpec
- Master difference between requestLayout() and invalidate()
- Understand trigger timing of drawing process
- Master basic steps of custom View
- Understand difference between hardware and software rendering