B06_XML控件布局与ViewBinding

Android 基础补强 B06|读懂 XML 布局:控件尺寸、父容器与 ViewBinding

摘要:从一张传统文章卡片出发,理解尺寸与布局参数、控件更新、资源复用和 ViewBinding,学会定位长标题及横屏布局问题。

标签:Android、XML、ViewBinding、布局、第一行代码

这一篇对应《第一行代码》第 3 版第 4 章,也是 28 天课程 D17 的基础补强。主项目使用 Compose,并不意味着存量 View 代码可以跳过。维护传统页面时,首先要看懂 XML 如何生成对象、父容器如何安排子控件,以及数据变化后谁来更新显示。文中布局与 Kotlin 片段未在现有工程编译,需放入独立练习页面验证。

1. 子控件的尺寸是交给父布局解释的

layout_width 和 layout_height 描述子控件向父容器提出的尺寸要求,match_parent 与 wrap_content 也要结合父容器约束理解。布局参数并不是每种容器都通用:LinearLayout 的权重、ConstraintLayout 的约束规则属于不同的父布局协议,不能看到 0dp 就一律理解为"不显示"。

例如水平 LinearLayout 中,标题宽度设为零并给权重,可以让它使用分配的剩余空间;若在没有相应规则的容器中机械复制,标题可能真的没有可用宽度。定位时先看父布局类型,再看尺寸、间距和约束,最后看文本自身的行数与截断设置。Android 布局指南

padding 位于控件内部,影响内容与控件边界;layout_margin 位于控件外部,由父布局布局时考虑。gravity 常控制容器内部内容对齐,layout_gravity 则要看父容器如何解释子控件位置。这些属性名字相似,但调整错误的一项会出现"怎么改都没反应"。

2. 用最小卡片观察布局变化

下面保存为 res/layout/activity_article_practice.xml。字符串资源需在 strings.xml 定义,bookmark_action 可为"收藏",sample_article_title 为示例标题。它只是练习布局,不包含项目主题、窗口边距等完整配置。

xml 复制代码
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal"
    android:gravity="center_vertical"
    android:padding="16dp">

    <TextView
        android:id="@+id/article_title"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:layout_marginEnd="12dp"
        android:maxLines="2"
        android:ellipsize="end"
        android:text="@string/sample_article_title"
        android:textSize="18sp" />

    <Button
        android:id="@+id/bookmark_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/bookmark_action" />
</LinearLayout>

标题使用剩余宽度,按钮按自身需要占位。文字单位使用 sp,布局尺寸使用 dp;用户放大字体后可用行数和高度需求会改变,不能只在默认字体下看截图。长标题超过两行时截断属于当前练习的产品选择,完整内容可以放在详情页,不应假装所有文章天然都很短。

资源也是结构的一部分。把文案放进字符串资源,才能集中管理翻译与格式;颜色、尺寸和样式需要复用时也应抽取。不要把"减少 XML 行数"当作唯一目标,过早嵌套很多通用布局同样可能增加理解成本。

3. ViewBinding 负责引用,不负责业务状态

模块启用 buildFeatures { viewBinding = true } 后,布局会生成相应 Binding 类。对于上面的文件,类名为 ActivityArticlePracticeBinding,控件 ID 对应可访问字段。Activity 中先 inflate,再把同一个 root 交给 setContentView,之后更新它的字段即可。ViewBinding 官方说明

下面放在练习 Activity 的 onCreate 中,需补齐 AppCompat 或 ComponentActivity 基类和布局资源。onBookmarkClicked 代表事件入口,应该交给状态持有者,而不是在此永久维护业务数据。

kotlin 复制代码
val binding = ActivityArticlePracticeBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.articleTitle.text = article.title
binding.bookmarkButton.isSelected = article.isBookmarked
binding.bookmarkButton.setOnClickListener {
    onBookmarkClicked(article.id)
}

ViewBinding 使控件访问具有生成的类型信息,但不会把普通变量变成可观察状态,也不会自动保存旋转后的收藏。状态仍要从 ViewModel 或 Repository 读取,再由渲染函数同步到控件。若把新布局 inflate 后只更新新 Binding,却仍然显示旧 root,就会出现"赋值执行了,屏幕没变"的对象错位。

Activity 与 Fragment 也不能完全复制同一套成员管理方式。Fragment 的 View 可先于 Fragment 销毁,需要在 onDestroyView 清理 Binding;B08 将详细解释。不能因为引用有类型,就认为它在任何生命周期时刻都有效。

4. 三个能定位问题的布局实验

第一组把短标题换成六十个字,并开启较大系统字体。预期按钮仍能操作,标题最多两行;如果按钮被挤出,应检查标题是否错误地使用全宽。记录横竖屏分别的现象,不只截最漂亮的一种尺寸。

第二组暂时去掉标题权重,但保留零宽度。预期标题区域不能再获得原来的剩余空间,从而直观理解零宽度必须配合父容器规则。恢复后把外边距改为内边距,观察两控件之间的距离与文字位置是否按预期变化。

第三组故意 inflate 两份布局,一份显示、一份赋值。预期第二份的内容变化不会出现在第一份屏幕上。用对象标识或调试器确认当前 root,随后恢复只持有显示树的实现。这些实验用于理解对象关系,不应作为保留在正式页面的代码。

5. 原创面试问答与追问

问一:为什么同样是 0dp,在不同布局里效果不同? 尺寸由父容器规则解释,权重或约束可能会再分配空间。追问:排错先看什么?先看父布局与对应 LayoutParams,而非只改数字。

问二:ViewBinding 能替代状态管理吗? 不能,它提供布局控件引用,业务状态与生命周期仍要设计。追问:按钮变色会自动持久化吗?不会,需要把事件写入相应数据来源。

问三:代码更新文字但页面没变化有哪些可能? 更新了未显示的 View、后续渲染覆盖、状态未被观察等。追问:怎样缩小范围?确认当前 root、赋值时机与模型来源,再检查渲染顺序。

以上为围绕书本知识原创的自测,不是面试鸭原题摘录。

6. 本专题验收

不看答案重建标题与按钮布局,说明每一个尺寸属性由谁解释;在长标题、大字体与横屏下检查行为;能把 ViewBinding 的引用便利和 ViewModel 的状态职责分开说明。完成这些基础后,再进入 D17 的传统列表与 Compose 互操作,就不会把所有问题都归因于框架不同。

相关推荐
晚风叙码2 小时前
MySQL 表的操作:从建表到删表,一篇讲清楚
android·mysql·oracle
事圆则缓3 小时前
Android 性能优化常见工具与使用场景:从症状到证据的排查指南
android·性能优化
avi91113 小时前
Unity 非后台,非自动构建,但统计报表 BuildReport ,构建自动化系统C#
android·webserver·ios打包·admin·c#后台·unity打包系统·unity自动构建
新鲜势力呀4 小时前
PHP 定时任务系统实战:从 Cron 混乱执行到任务调度中心 + Redis队列 + 失败重试
android·java·redis
YF02114 小时前
Android 16系统 如何修改 eth0 IP ?
android
其实防守也摸鱼4 小时前
渗透测试学习计划(全栈综合 · 零基础进阶)
android·数据库·学习·安全·oracle·自动化·学习方法
释厄6235 小时前
BSD 简单真理循环论——简单真理 × 复杂循环=大一统
android·开发语言·kotlin
Brilliantwxx6 小时前
【STM32】 DMA 源码分析与实战(下):DMA 收发状态机与 HAL 分层
android·开发语言·stm32·单片机·嵌入式硬件·mcu
ao-weilai6 小时前
MySQL数据库:数据类型
android·数据库·mysql