Android 布局控件之 LinearLayout 和 RelativeLayout

778 阅读4分钟

这是我参与8月更文挑战的第17天,活动详情查看:8月更文挑战

文章目录

Android 七大基本布局分别是:
线性布局 LinearLayout
相对布局 RelativeLayout
表格布局 TableLayout
层布局 FrameLayout
网格布局 GridLayout
绝对布局 AbsoluteLayout
约束布局 ConstraintLayout

LinearLayout

有什么比官方文档写的更好呢:Android Developers LinearLayout

线性布局 LinearLayout,指的是整个 Android 布局中的控件摆放方式是以线性的方式摆放的。

布局方向

orientation="horizontal"   水平(默认)
orientation="vertical"  垂直

比重,比例
按比例来分配剩余可用空间。使用权重一般要把分配该权重方向的长度设置为零,比如在水平方向分配权重,就把 width 设置为零

layout_weight="1"

重力

layout_gravity="可选值"

layout_gravity 子元素在父元素的对齐方式,设置在子元素上

android:orientation="vertical" 时,只有水平方向的设置才起作用,垂直方向的设置不起作用,即:leftrightcenter_horizontal 是生效的
android:orientation="horizontal" 时,只有垂直方向的设置才起作用,水平方向的设置不起作用,即:topbottomcenter_vertical 是生效的

还有一个跟 它 很相似的属性

android:gravity="可选值"

gravity 是控制控件布局对齐方式的。可选值为 buttom、left、right、center_vertical、fill_vertical、center_horizontal、fill_horizontal、center、fill、clip_vertical、clip_horizontal

可以同时使用多个参数,需要用|符号分隔开,比如在 TextView 控件里的文本需要靠在右上角就要添加以下属性android:gravity="top|right"

android:layout_gravityandroid:gravity 的区别:
android:gravity="bottom|right"(是本元素所有子元素的对齐方式,设置在父元素上)
android:layout_gravity (子元素在父元素的对齐方式,设置在子元素上)

权重是对于新手比较难理解的,所以这里重点练习下权重。其他看官方文档就很容易理解了

线性布局练习

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:text="btn1" />

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_weight="2"
        android:text="btn2" />

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="btn3" />

</LinearLayout>

运行程序:
在这里插入图片描述
btn3 有一个高度。btn1 和 btn2 按照 1:2 的比例瓜分这剩余的高度。

RelativeLayout

有什么比官方文档写的更好呢:Android Developers RelativeLayout

停靠父控件边界

alignParentTop
alignParentBottom
alignParentLeft
alignParentRight

相对父控件居中

centerInParent
centerHorizontal
centerVertical

停靠周围控件边界

above
below
toRightOf
toLeftOf

与周围控件边界对齐

alignTop
alignBottom
alignLeft
alignRight
alignBaseLine

看起来上边的属性非常多,其实非常好理解,下面通过一个例子来实践下,相信你看了就懂

相对布局练习

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <!--
        @+id新定义id
        在R类中新定义一个整数常量
        如果常量已存在就引用现有常量
        @id引用id

        在引用id时也可以使用@+id
        但是如果写错的已存在的id就会新创建一个整数常量
        所以为了严谨应该用@id
    -->
    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="btn1" />

    <Button
        android:id="@+id/button2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true"
        android:text="btn2" />

    <Button
        android:id="@+id/button3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_alignParentRight="true"
        android:text="btn3" />

    <Button
        android:id="@+id/button4"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_centerVertical="true"
        android:text="btn4" />

    <Button
        android:id="@+id/button5"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:text="btn5" />

    <Button
        android:id="@+id/button6"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_centerVertical="true"
        android:text="btn6" />

    <Button
        android:id="@+id/button7"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentBottom="true"
        android:text="btn7" />

    <Button
        android:id="@+id/button8"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:text="btn8" />

    <Button
        android:id="@+id/button9"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_alignParentBottom="true"
        android:text="btn9" />

    <Button
        android:id="@+id/button10"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_above="@id/button4"
        android:layout_below="@id/button1"
        android:layout_alignRight="@id/button2"
        android:layout_toRightOf="@id/button1"
        android:text="btn10" />

    <Button
        android:id="@+id/button11"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_above="@id/button7"
        android:layout_alignTop="@id/button4"
        android:layout_toLeftOf="@id/button5"
        android:layout_toRightOf="@id/button4"
        android:text="btn11" />

    <Button
        android:id="@+id/button12"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBaseline="@id/button11"
        android:layout_toLeftOf="@id/button6"
        android:layout_toRightOf="@id/button11"
        android:text="btn12" />
</RelativeLayout>

运行结果:
在这里插入图片描述

如何选择

分析
1、RelativeLayout 分别对所有子 View 进行两次 measure,横向纵向分别进行一次

2、LinearLayout 首先会对所有的子 View 进行 measure,并计算 totalWeight (所有子 View 的 weight 属性之和),然后判断子 View 的 weight 属性是否为最大,如为最大则将剩余的空间分配给它。如果不使用 weight 属性进行布局,则不进行第二次 measure

由此可见,weight 属性对性能是有影响的

3、如果他们位于整个 View 树的顶端时并可能进行多层的嵌套时,位于底层的 View 将会进行大量的 measure 操作,大大降低程序性能。因此,应尽量将 RelativeLayout 和 LinearLayout 置于 View 树的底层,并减少嵌套

结论
1、RelativeLayout 慢于 LinearLayout 是因为它会让子 View 调用2次 measure 过程,而 LinearLayout 只需一次,但是有 weight 属性存在时,LinearLayout 也需要两次measure。

2、RelativeLayout 的子 View 如果高度和 RelativeLayout 不同,会导致 RelativeLayout 在 onMeasure() 方法中做横向测量时,纵向的测量结果尚未完成,只好暂时使用自己的高度传入子 View 系统。而父 View 给子 View 传入的值也没有变化就不会做无谓的测量的优化会失效,解决办法就是可以使用 padding 代替margin 以优化此问题。
3、在不响应层级深度的情况下,使用 Linearlayout 而不是 RelativeLayout。

4、而为开发者默认新建 RelativeLayout 是希望开发者能采用尽量少的 View 层级,很多效果是需要多层 LinearLayout 的嵌套,这必然不如一层的 RelativeLayout 性能更好。因此我们应该尽量减少布局嵌套,减少层级结构,使用比如 viewStub、include 等技巧,可以进行较大的布局优化。

当然了官方现在强推 约束布局:ConstraintLayout。将在接下来的文章中重点讲解。