Android布局XML中的merge, include, ViewStub标签怎么用

12次阅读

merge不是View,不能设宽高/边距/ID;includeandroid:id仅作用于被引入布局的根View(根为merge时无效);ViewStub需调用setVisibility(VISIBLE)或inflate()才加载——三者定位不同,混用会导致findViewById失败、层级冗余或界面空白。

Android布局XML中的merge, include, ViewStub标签怎么用

merge 不是 View,不能设宽高/边距/ID;includeandroid:id 只作用于被引入布局的根 View(若根是 则无效);ViewStub 必须调用 setVisibility(View.VISIBLE)inflate() 才真正加载——三者定位完全不同,混用或错配会直接导致 findViewById 失败、层级冗余或界面空白。

include 标签:复用布局时怎么设 ID 和 layout_* 属性?

你写 ,这个 android:id 会被赋给 title_bar.xml 的根 View。但前提是它的根不能是 ——否则 ID 丢失,findViewById(R.id.title1) 返回 NULL

  • 必须同时重写 android:layout_widthandroid:layout_height,单写一个无效
  • 边距(如 android:layout_marginTop)也只在宽高都重写后才生效
  • title_bar.xml 根是 ,且你 include 两次,记得给两个 分别设不同 android:id,否则 findViewById 只能拿到第一个
  • 根是 时,ID 无效 → 改用 findViewById(R.id.tv_title) 直接找子控件(需确保不重名)

merge 标签:什么情况下必须用?为什么设了属性没反应?

是占位符,不是 View,所以所有 XML 属性(android:layout_widthandroid:backgroundandroid:id)全被忽略——这是设计使然,不是 bug

  • 只允许作为 XML 文件的**根节点**,否则解析失败
  • 典型场景:被 引入的布局,其根 ViewGroup 类型和父容器一致(比如父是 ,被 include 的也是 ),这时换成 就能砍掉一层嵌套
  • 自定义 View 的 layout 文件根节点建议用 ,避免多包一层无意义容器
  • 注意:用 LayoutInflater.inflate(R.layout.xxx, parent, true) 加载含 的布局时,parent 必须非 null,且第三个参数必须为 true,否则 merge 内容不会 attach 到父容器

ViewStub:为什么设置了 layout 却不显示?

初始化时是 0x0 的不可见占位符,它**不会解析内部 layout,也不创建任何子 View**——直到你主动触发。

  • 两种激活方式(二选一):
     ✓ viewStub.setVisibility(View.VISIBLE) —— 自动 inflate 并替换自身
     ✓ View inflated = viewStub.inflate() —— 返回加载后的根 View,可继续 findViewById 操作
  • inflate 后 ViewStub 对象失效,再次调用 inflate()IllegalStateException
  • 不能在 上设 android:visibility="gone" 来“预隐藏”,它只认 invisiblevisible(但初始就是 invisible)
  • 适合放错误页、加载中提示、横竖屏专用布局等「非首屏必需」内容,避免拖慢启动速度

最容易被忽略的是:merge 的属性一律无效、include 的 ID 在 merge 下消失、ViewStub 不调用就不加载——这三个行为不是缺陷,而是机制设计。写布局时先想清楚「我要复用?减层?还是懒加载?」,再选标签,比死记语法重要得多。

text=ZqhQzanResources