4、布局基础(一):LinearLayout线性布局、RelativeLayout相对布局、常用属性

各位同学,欢迎来到布局的世界。

说实话,布局是Android开发的基石。你写的界面好不好看,适配性怎么样,全看布局用得熟不熟。我刚开始学的时候,也踩过不少坑,比如一个界面怎么调都歪,或者在不同手机上直接崩了。嗯,今天咱们就把最常用的两个布局讲透。

4.1 LinearLayout:线性布局

LinearLayout,说白了就是「排排坐」。它会把里面的子控件按一个方向排好,要么横着排,要么竖着排。

怎么控制方向?用 android:orientation 属性:

  • vertical:垂直排列(从上到下)
  • horizontal:水平排列(从左到右)

举个例子,一个简单的登录界面:

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="16dp">

    <EditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="请输入用户名" />

    <EditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="请输入密码"
        android:inputType="textPassword" />

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="登录" />

</LinearLayout>

你看,三个控件从上到下排得整整齐齐。我在项目中经常用这种方式做表单,简单又稳定。

小提示:如果子控件太多,垂直方向排不下怎么办?可以套一个 ScrollView,但那是后面章节的内容了。

4.2 RelativeLayout:相对布局

RelativeLayout 就灵活多了。它允许你指定子控件相对于父容器或者其他兄弟控件的位置。

比如「A在B的右边」、「C在父容器的底部居中」。这种布局在复杂界面里特别有用。

看个例子:

<RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:id="@+id/btn_ok"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:text="确定" />

    <Button
        android:id="@+id/btn_cancel"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_toRightOf="@id/btn_ok"
        android:layout_alignTop="@id/btn_ok"
        android:text="取消" />

</RelativeLayout>

这里「确定」按钮居中,「取消」按钮在它的右边,并且顶部对齐。是不是很直观?

注意:RelativeLayout 的布局计算比 LinearLayout 复杂,嵌套多了会影响性能。我曾经在一个列表项里用了三层 RelativeLayout,结果滑动卡得不行。后来改成一层 LinearLayout + 一层 RelativeLayout,流畅多了。

4.3 常用属性详解

4.3.1 gravity:对齐方式

android:gravity 控制的是「内容」在容器里的对齐方式。比如文字在按钮里是左对齐还是居中。

常用值:

效果
left 左对齐
center 水平垂直居中
center_horizontal 水平居中
center_vertical 垂直居中
right 右对齐

注意区分 gravitylayout_gravity。前者是内容在自身里的对齐,后者是自身在父容器里的对齐。我刚开始也搞混过,后来记住一句话:不带 layout 的是管自己,带 layout 的是管爸爸

4.3.2 layout_weight:权重

这个属性只在 LinearLayout 里有效。它用来按比例分配剩余空间。

举个例子:

<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="2"
        android:text="右" />

</LinearLayout>

这里两个按钮会按 1:2 的比例平分宽度。「左」占三分之一,「右」占三分之二。

关键点:使用权重时,建议把 layout_width(水平方向)或 layout_height(垂直方向)设为 0dp。这样系统就知道「你不用管自己的大小,我来按权重分」。否则容易算出奇怪的结果。

我记得有一次,同事没设 0dp,结果权重怎么调都不对。折腾了半天才发现是宽度设了 wrap_content。嗯,这种坑踩过一次就记住了。

4.3.3 padding 与 margin

这两个属性都用来控制间距,但作用对象不同:

  • padding:内边距。控件的内容区域到控件边框的距离。
  • margin:外边距。控件边框到其他控件或父容器边框的距离。

你可以理解为:padding 是「给自己留点空间」,margin 是「给别人留点空间」。

看代码:

<Button
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:padding="16dp"
    android:layout_margin="8dp"
    android:text="点我" />

这个按钮的文字距离按钮边缘有 16dp 的内边距,按钮距离其他控件有 8dp 的外边距。

经验之谈:我一般用 padding 来让按钮看起来「大气一点」,用 margin 来调整控件之间的间距。比如列表项之间用 margin,按钮内部的文字用 padding。

另外,padding 和 margin 都可以单独设置四个方向:

  • android:paddingLeftandroid:paddingTopandroid:paddingRightandroid:paddingBottom
  • android:layout_marginLeftandroid:layout_marginTopandroid:layout_marginRightandroid:layout_marginBottom

也可以统一设置:android:padding="16dp" 表示四个方向都是 16dp。

4.4 小结

今天讲了 LinearLayout 和 RelativeLayout 这两个最基础的布局,还有 gravity、layout_weight、padding 和 margin 这几个常用属性。

你想想看,其实布局就是「把控件放到合适的位置」。LinearLayout 适合简单的线性排列,RelativeLayout 适合复杂的相对定位。至于属性,多用几次就熟了。

下一节我们会讲 ConstraintLayout,那是现在最主流的布局方式。嗯,到时候你会发现,原来布局可以这么灵活。

课后练习:用 LinearLayout 和 RelativeLayout 分别实现一个「顶部标题 + 中间内容 + 底部按钮」的界面。试试用 padding 和 margin 调整间距,看看效果有什么不同。

公众号:蓝海资料掘金营,微信deep3321