3、线性布局(LinearLayout):orientation属性、weight权重分配、gravity与layout_gravity区别、实战:登录界面布局

好,咱们今天来聊聊 LinearLayout。这个布局,说白了就是 Android 里最基础、最常用的一个容器。你想想看,大部分界面其实都是一行一行、一列一列堆出来的。LinearLayout 就是干这个的——把子 View 按水平或垂直方向排成一条线。

我个人习惯,在写简单列表或表单时,第一个想到的就是它。因为它够简单,够直观。但别小看它,用好了,效率非常高。

3.1 orientation 属性:横着排还是竖着排?

orientation 就两个值:horizontalvertical。一个横着排,一个竖着排。嗯,就这么简单。

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal">

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="按钮1" />

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="按钮2" />

</LinearLayout>

上面这段代码,两个按钮会并排显示。如果改成 vertical,它们就上下叠在一起。我在项目中遇到过一个问题:新手经常忘记设置 orientation,结果所有子 View 都叠在一起了。默认值是 horizontal,但如果你不写,IDE 会给你一个警告。所以,养成好习惯,每次都用上。

3.2 weight 权重分配:让空间分配更灵活

weight 是 LinearLayout 里最强大的特性之一。它允许你按比例分配剩余空间。说白了,就是告诉系统:「剩下的空间,按这个比例分给各个子 View」。

举个例子,你想让两个按钮各占一半宽度:

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal">

    <Button
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:text="左边" />

    <Button
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:text="右边" />

</LinearLayout>

这里有个关键点:layout_width="0dp"。为什么要设成 0?因为我们要让 weight 来决定宽度,而不是让内容撑开。你想想看,如果设成 wrap_content,系统会先计算内容宽度,再分配剩余空间,结果往往不是你想要的。

小技巧: 我建议在水平布局中,把 layout_width 设成 0dp;在垂直布局中,把 layout_height 设成 0dp。这样 weight 才能完全控制尺寸。

weight 的计算公式其实很简单:

最终大小 = 自身大小 + (剩余空间 × 自身权重 / 总权重)

当所有子 View 的宽度都设为 0dp 时,自身大小为 0,最终大小就完全由权重决定了。比如两个按钮权重都是 1,总权重是 2,剩余空间是父容器宽度,那么每个按钮就分到一半。

我曾经踩过一个坑:在垂直布局里,给一个 TextView 设了 layout_height="wrap_content"layout_weight="1",结果它并没有填满剩余空间。为什么?因为 wrap_content 让它的自身高度占了很大一部分,剩余空间就少了。后来改成 0dp,问题就解决了。

3.3 gravity 与 layout_gravity 区别

这两个名字很像,但作用对象完全不同。很多新手会搞混,我刚开始也迷糊过一阵子。

属性 作用对象 作用范围
android:gravity 当前 View 内部的子 View 或内容 控制内部元素的对齐方式
android:layout_gravity 当前 View 在父容器中的位置 控制自身在父容器中的对齐方式

举个例子,一个 LinearLayout 设置了 android:gravity="center",那么它里面的所有子 View 都会居中显示。而如果某个 Button 设置了 android:layout_gravity="right",那么这个 Button 会靠右对齐到父容器。

嗯,这里要注意:layout_gravity 只在父容器是 LinearLayout 时有效,而且受 orientation 影响。比如在水平 LinearLayout 中,layout_gravity 只能控制垂直方向的对齐(top、bottom、center_vertical),水平方向由 orientation 决定。

避坑指南: 我曾经在水平 LinearLayout 里给一个子 View 设了 layout_gravity="left",结果发现没效果。后来才意识到,水平方向的对齐是由 orientation 控制的,layout_gravity 只影响垂直方向。所以,别搞混了。

3.4 实战:登录界面布局

好了,理论说完了,咱们来写个实际的登录界面。这个界面很常见,但用 LinearLayout 实现起来非常清晰。

先分析一下布局结构:

  • 一个垂直的 LinearLayout 作为根容器
  • 里面放一个 Logo 图片(居中)
  • 然后是用户名输入框
  • 密码输入框
  • 登录按钮
  • 底部可以加一个「忘记密码」的链接
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:gravity="center_horizontal"
    android:padding="24dp">

    <!-- Logo 区域 -->
    <ImageView
        android:layout_width="80dp"
        android:layout_height="80dp"
        android:src="@drawable/ic_logo"
        android:layout_marginBottom="32dp"
        android:contentDescription="应用图标" />

    <!-- 用户名输入框 -->
    <EditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="请输入用户名"
        android:inputType="text"
        android:padding="12dp"
        android:layout_marginBottom="16dp"
        android:background="@drawable/edit_text_bg" />

    <!-- 密码输入框 -->
    <EditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="请输入密码"
        android:inputType="textPassword"
        android:padding="12dp"
        android:layout_marginBottom="24dp"
        android:background="@drawable/edit_text_bg" />

    <!-- 登录按钮 -->
    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="登录"
        android:padding="12dp"
        android:layout_marginBottom="16dp" />

    <!-- 忘记密码链接 -->
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="忘记密码?"
        android:textColor="@color/colorAccent"
        android:gravity="center" />

</LinearLayout>

这个布局有几个要点:

  • 根容器用了 gravity="center_horizontal",让所有子 View 水平居中
  • 输入框和按钮都用了 match_parent,宽度填满屏幕,但受 padding 限制
  • 每个元素之间用 layout_marginBottom 拉开间距,这样看起来更舒服

如果你想让登录按钮和忘记密码之间留出更多空间,可以用一个空 View 配合 weight:

<!-- 在按钮和忘记密码之间加一个占位空间 -->
<View
    android:layout_width="match_parent"
    android:layout_height="0dp"
    android:layout_weight="1" />

这样,登录按钮会紧贴输入框,而忘记密码会被推到屏幕底部。嗯,这个小技巧我在很多项目里都用过,非常实用。

核心总结:
  • orientation 决定排列方向,别忘了设置
  • weight 分配剩余空间,配合 0dp 使用效果最佳
  • gravity 控制内部内容,layout_gravity 控制自身位置,别搞混
  • 实战中多用 margin 和 padding 调整间距,让界面更清爽

好了,这一章就到这里。LinearLayout 虽然基础,但用好了能解决大部分布局需求。下一章咱们聊聊 RelativeLayout,那个更灵活,但也更容易踩坑。到时候我再分享一些我的实战经验。