本节摘要:Android 的一切界面都由一棵视图树构成——叶子节点是 View(按钮、文本等可直接绘制的控件),枝干节点是 ViewGroup(LinearLayout 等负责摆放子节点的容器)。本节讲清这棵树如何生长、Activity 如何挂载它,以及工具 Layout Inspector 如何让你亲眼看到它。
把 1.1 节那份猜数字布局放到解剖台上,它其实是这样一棵树:最外层 LinearLayout 是根,往下分出 TextView、EditText、Button 三个叶子。再往上追,系统还有更多默认层级——Activity 持有 Window,Window 持有 DecorView,DecorView 里才是你的布局。整条链是:
Activity → Window → DecorView → 你的 ViewGroup → 各个子 View
为什么非要用树?因为"容器套控件"是表达复杂界面成本最低的方式:登录页是一个竖直容器,里面每一行又是一个水平容器,行里再放图标和输入框。树形嵌套天然匹配这种结构。代价是层次一多性能会下降,所以 Android 后来力推更扁的 ConstraintLayout,这在第 4 章会详细对比。
用类关系看更准确:ViewGroup 继承自 View,同时内部持有若干子 View 的引用。也就是说,容器本身也是 View,所以容器可以套容器,树可以任意深。
// View 与 ViewGroup 的关系(示意,非源码) open class View(...) // 能画、能响应事件 open class ViewGroup(...) : View(...) { val children = mutableListOf<View>() fun addView(child: View) { children.add(child) } } // LinearLayout、FrameLayout、ConstraintLayout 都是 ViewGroup 的子类 // TextView、Button、ImageView 是 View 的子类(Button 其实也继承 TextView)
注意最后一行的冷知识:Button 继承自 TextView。所以 Button 能设置文字颜色、字号,一点也不奇怪——它本来就是个被赋予了点击样式的文本控件。
XML 的标签嵌套就是这棵树的字面翻译。看一个"输入框 + 右侧清除按钮"的行结构,它套进猜数字主布局后就是两层容器:
<!-- 一行:水平排列的容器包住输入框和小按钮 --> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:gravity="center_vertical"> <EditText android:id="@+id/et_guess" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:hint="输入 1 到 100 之间的整数" android:inputType="number" /> <ImageButton android:id="@+id/btn_clear" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@android:drawable/ic_input_delete" android:contentDescription="清空输入" /> </LinearLayout>
三个尺寸取值的含义必须现在记牢,它们出现在每一份布局里:
match_parent:与父容器同宽/同高,撑满;wrap_content:刚好包住自己的内容,字多就宽、字少就窄;48dp:写死多大就多大。内层 EditText 用 0dp + weight=1 的组合表示"占满剩余宽度",这是 LinearLayout 的经典手法,4.1 节专门展开。
抽象讲十遍不如看一次。Android Studio 里运行猜数字 App,打开布局检查器,屏幕左侧会出现实时视图树:根节点往下一层层展开,右侧同步高亮你在模拟器上选中的控件,还标注了每个节点的宽高与 margin。排查"这个控件怎么看不见""为什么被挤出去"这类问题时,先来这里看树,比盯着 XML 猜高效得多。

⚠️ 常见坑:层级过深。每多一层 ViewGroup,测量与绘制的开销就多一轮传递,嵌套七八层的列表项会直接掉帧。看到自己写出四层以上纯装饰性嵌套时,就该考虑换布局或用 ConstraintLayout 压扁。
视图树这么抽象,我怎么亲眼看到它? 不用背理论,两分钟就能见到实物:打开 Android Studio 的布局检查器(第 8 章会正式讲),连上运行中的 App,左侧 Component Tree 面板里出现的就是真实视图树,展开任何一个节点都能看到它测量出的宽高。把猜数字 App 的树和手画的草图对一遍,层级模型就从概念变成了亲眼所见。
层级越深越不好吗? 测量成本确实随嵌套深度翻倍增长,第 4 章会给出"三层即警觉"的经验线。但初学阶段不必为压扁层级而过度设计——先能正确表达结构,再学着优化,ConstraintLayout 的价值要到那时才真正显现。
一个界面只能有一棵树吗? 不是。Dialog 与 PopupWindow 各有自己的窗口树,但只要记住"每棵树都有自己的根、树内规则一致",多窗口也只是多几棵树而已,模型并未升级。