5月29日 23:47
Android View 的绘制流程是怎样的?
View 的绘制流程一句话就是:从 ViewRootImpl 发起,依次执行 measure、layout、draw。measure 负责算宽高,核心是父 View 传下来的 MeasureSpec;layout 负责确定 left、top、right、bottom;draw 负责真正画到 Canvas 上。自定义 View 里最常见的问题是只重写 onDraw,却忘了在 onMeasure 处理 wrap_content。尺寸或位置变化用 requestLayout,内容变化用 invalidate,别混着用。
追问
MeasureSpec 有哪几种模式?
EXACTLY 表示确定尺寸,常见于固定 dp 或 match_parent;AT_MOST 表示最大不能超过某个值,常见于 wrap_content;UNSPECIFIED 表示父容器不限制,ScrollView 测子 View 时可能出现。
ViewGroup 和普通 View 的绘制有什么区别?
ViewGroup 在 measure 阶段要测量子 View,在 layout 阶段摆放子 View,在 draw 阶段通过 dispatchDraw 绘制子 View。普通 View 通常只关心自己的测量和 onDraw。
requestLayout 和 invalidate 有什么区别?
requestLayout 会重新走 measure、layout,必要时再 draw;invalidate 只触发重绘。改文字大小、宽高、位置用 requestLayout,改颜色、进度、选中态通常用 invalidate。
实际项目里容易踩什么坑?
自定义 View 如果 wrap_content 不设置默认尺寸,可能测出来是 0 或不符合预期。另一个坑是在 onDraw 里频繁 new Paint、Path、Rect,会造成 GC 抖动和掉帧。
写段代码
java@Override protected void onMeasure(int widthSpec, int heightSpec) { int defaultW = dp(120); int defaultH = dp(48); int w = resolveSize(defaultW, widthSpec); int h = resolveSize(defaultH, heightSpec); setMeasuredDimension(w, h); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawCircle(getWidth() / 2f, getHeight() / 2f, radius, paint); }