1 线性布局

LinearLayout

// 布局方向
orientation="vertical/horizontal"
// 子元素的对齐方式
gravity="left|buttom"
// 控制该组件在父容器的对齐方式
layout_gravity

// 权重,将剩余部分等比划分
weight

// 分割线图片
divider
// 设置分割线位置,none/middle/begining/end
showDividers
// 分割线 padding
dividerPadding

当 android:orientation=“vertical” 时, 只有水平方向的设置才起作用,垂直方向的设置不起作用。 即:left,right,center_horizontal 是生效的。 当 android:orientation=“horizontal” 时, 只有垂直方向的设置才起作用,水平方向的设置不起作用。 即:top,bottom,center_vertical 是生效的。

weight 权重

将剩余空间按权重划分。

当 width 为 0dp 或者 wrap_content 的时候没有问题。

当子控件 width 为 match_parent 会出现问题

// 控件1
android:layout_weight="1"    
android:layout_width="fill_parent" 
// 控件2
android:layout_weight="2
android:layout_width="fill_parent" 
// 控件3
android:layout_weight="3
android:layout_width="fill_parent"

发现比例为 2:1:0 ,

step 1:个个都是fill_parent,但是屏幕只有一个啦,那么1 - 3 = - 2 fill_parent

step 2:依次比例是1/6,2/6,3/6

step 3:剩余空间为 -2 fill_parent,先到先得,先分给one,计算: 1 + (- 2 * (1/6)) = 2/3 fill_parent ,接着到two,计算: 1 + ( - 2 * (2/6)) = 1/3 fill_parent, 最后到three,计算 1 + ( - 2 * (3/6)) = 0 fill_parent

2 相对布局

RelativeLayout

可以相对于某一控件或者父容器对齐

所有控件从左上角开始

基本属性

// 设置容器内组件的对齐方式
gravity
设置了该属性为true的属性的组件,将不受 gravity 属性的影响
ignoreGravity

根据父容器定位

// 左对齐
layout_alignParentLeft
// 右对齐
layout_alignParentRight
// 顶部对齐
layout_alignParentTop
// 底部对齐
layout_alignParentBottom
// 水平居中
layout_centerHorizontal
// 垂直居中
layout_centerVertical
// 中间位置
layout_centerInParent

根据兄弟组件定位

// 参考组件的左边
layout_toleftOf
// 参考组件的右边
layout_toRightOf
// 参考组件的上方
layout_above
// 参考组件的下方
layout_below
// 对齐参考组件的上边界
layout_alignTop
// 对齐参考组件的下边界
layout_alignBottom
// 对齐参考组件的左边界
layout_alignLeft
// 对齐参考组件的右边界
layout_alignRight

margin 偏移

// 设置组件上下左右的偏移量
layout_margin
// 设置组件离左边的偏移量
layout_marginLeft
// 设置组件离右边的偏移量
layout_marginRight
// 设置组件离上面的偏移量
layout_marginTop
// 设置组件离下面的偏移量
layout_marginBottom

padding 填充,padding 会影响组件自身大小

// 往内部元素的上下左右填充一定边距
padding
// 往内部元素的左边填充一定边距
paddingLeft
// 往内部元素的右边填充一定边距
paddingRight
// 往内部元素的上方填充一定边距
paddingTop
// 往内部元素的下方填充一定边距
paddingBottom

3 帧布局

FrameLayout

只能放在(top,center,bottom)*(left,center,right) 9 个位置

// 前景图像:永远处于帧布局最上面,直接面对用户的图像,就是不会被覆盖的图片。
// 设置改帧布局容器的前景图像
foreground
// 设置前景图像显示的位置
foregroundGravity
// 指定控件的对齐方式
android:layout_gravity="bottom"
android:layout_gravity="center_vertical"
// 垂直居中并靠右
android:layout_gravity="center_vertical|right"

4 表格布局

TableLayout 不常用,类似于竖直方向的线性布局

<TableRow> :声明控件在一行

确定行数和列数

  • 如果我们直接往 TableLayout 中添加组件的话,那么这个组件将占满一行!!!
  • 如果我们想一行上有多个组件的话,就要添加一个 TableRow 的容器,把组件都丢到里面!
  • tablerow 中的组件个数就决定了该行有多少列,而列的宽度由该列中最宽的单元格决定
  • tablerow 的 layout_width 属性,默认是 fill_parent 的,我们自己设置成其他的值也不会生效!!! 但是 layout_height 默认是 wrapten-content的,我们却可以自己设置大小!
  • 整个表格布局的宽度取决于父容器的宽度(占满父容器本身)
  • 有多少行就要自己数啦,一个 tablerow 一行,一个单独的组件也一行!多少列则是看 tableRow 中的组件个数,组件最多的就是 TableLayout 的列数

常用属性

// 设置需要被隐藏的列的序号
collapseColumns
// 设置允许被收缩的列的列序号,为了保证表格能适应父容器的宽度
shrinkColumns
// 设置运行被拉伸的列的列序号,填满剩余空间
stretchColumns

以上这三个属性的列号都是从 0 开始算的,比如 shrinkColunmns = "2",对应的是第三列!
可以设置多个,用逗号隔开比如"0,2",如果是所有列都生效,则用"*"号即可
除了这三个常用属性,还有两个属性,分别就是跳格子以及合并单元格,这和HTML中的Table类似:

// 表示的就是跳过第二个,直接显示到第三个格子处,从1开始算的!
layout_column="2"
// 表示合并4个单元格,也就说这个组件占4个单元格
android:layout_span="4"

5 网格布局

GridLayout

使用虚细线将布局划分为行、列和单元格,也支持一个控件在行、列上都有交错排列。

// 排列方式
orientation="vertical/horizontal"
// 对齐方式
gravity="center/left/right/bottom"

// 布局的行列数
rowCount="4"
columnCount="4"

// 组件起始行列
layout_row="1"
layout_column="2"

// 组件跨越行列数
layout_rowSpan="2"
layout_columnSpan="3"

设置了组件横跨多行或者多列的话,如果你要让组件填满横越过的行或列的话,需要添加下面这个属性: layout_gravity = “fill”

绝对布局

AbsoluteLayout 已过时

// 设置组件的X坐标
layout_x
// 设置组件的Y坐标
layout_y

6 约束布局

参考:约束布局ConstraintLayout看这一篇就够了

缺点:约束太强,不利于维护,牵一发而动全身

位置约束

// 左边约束在所选控件的左边
layout_constraintLeft_toLeftOf
// 左边约束在所选控件的右边
layout_constraintLeft_toRightOf
layout_constraintRight_toLeftOf
layout_constraintRight_toRightOf
layout_constraintTop_toTopOf
layout_constraintTop_toBottomOf
layout_constraintBottom_toTopOf
layout_constraintBottom_toBottomOf
layout_constraintBaseline_toBaselineOf
layout_constraintStart_toEndOf
layout_constraintStart_toStartOf
layout_constraintEnd_toStartOf
layout_constraintEnd_toEndOf

角度约束

layout_constraintCircle="@+id/TextView1"
layout_constraintCircleAngle="120"(角度)
layout_constraintCircleRadius="150dp"(距离)

margin 约束

layout_marginStart
layout_marginEnd
layout_marginLeft
layout_marginTop
layout_marginRight
layout_marginBottom

约束布局中必须约束一个相对位置 margin 才生效

goneMargin

// goneMargin 主要用于约束的控件可见性,约束控件被设置为 gone 的时候使用的 margin 生效
layout_goneMarginStart
layout_goneMarginEnd
layout_goneMarginLeft
layout_goneMarginTop
layout_goneMarginRight
layout_goneMarginBottom

居中

layout_constraintBottom_toBottomOf="parent"
layout_constraintLeft_toLeftOf="parent"
layout_constraintRight_toRightOf="parent"
layout_constraintTop_toTopOf="parent"

偏移

// 水平偏移
layout_constraintHorizontal_bias="0.5"  // 0 最左侧,1 最右侧
// 垂直偏移
layout_constraintVertical_bias

尺寸约束

minWidth  // 最小的宽度
minHeight // 最小的高度
maxWidth  // 最大的宽度
maxHeight // 最大的高度

// 官方不推荐在 ConstraintLayout 中使用 match_parent,可以设置 0dp

宽高比

layout_constraintDimensionRatio="1:1"
// 已知宽求高,已宽为基准求高
app:layout_constraintDimensionRatio="H,2:3"
// 已知高求宽,已高为基准就宽
app:layout_constraintDimensionRatio="W,2:3"

如果两个或以上控件通过下图的方式约束在一起,就可以认为是他们是一条链(图为横向的链,纵向同理)。

2787721b3b5a73715891a53.webp

用代码表示:

<TextView
        android:id="@+id/TextView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toLeftOf="@+id/TextView2" />

<TextView
    android:id="@+id/TextView2"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:layout_constraintLeft_toRightOf="@+id/TextView1"
    app:layout_constraintRight_toLeftOf="@+id/TextView3"
    app:layout_constraintRight_toRightOf="parent" />

<TextView
    android:id="@+id/TextView3"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:layout_constraintLeft_toRightOf="@+id/TextView2"
    app:layout_constraintRight_toRightOf="parent" />
layout_constraintHorizontal_chainStyle 来改变整条链的样式。chains提供了3种样式
CHAIN_SPREAD —— 展开元素 (默认);
CHAIN_SPREAD_INSIDE —— 展开元素,但链的两端贴近parent;
CHAIN_PACKED —— 链的元素将被打包在一起。

27877216d3fd9ce0f0cfd75.webp

权重链

<TextView
    android:id="@+id/TextView1"
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toLeftOf="@+id/TextView2"
    app:layout_constraintHorizontal_weight="2" />

<TextView
    android:id="@+id/TextView2"
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    app:layout_constraintLeft_toRightOf="@+id/TextView1"
    app:layout_constraintRight_toLeftOf="@+id/TextView3"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintHorizontal_weight="3" />

<TextView
    android:id="@+id/TextView3"
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    app:layout_constraintLeft_toRightOf="@+id/TextView2"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintHorizontal_weight="4" />

7 约束布局辅助工具

Barrier

假设有 3 个控件 ABC,C 在 AB 的右边,但是 AB 的宽是不固定的,这个时候 C 无论约束在 A 的右边或者 B 的右边都不对。当出现这种情况可以用 Barrier 来解决。Barrier 可以在多个控件的一侧建立一个屏障,如下所示:

这个时候 C 只要约束在 Barrier 的右边就可以了,代码如下:

<TextView
    android:id="@+id/TextView1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />

<TextView
    android:id="@+id/TextView2"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:layout_constraintTop_toBottomOf="@+id/TextView1" />

<android.support.constraint.Barrier
    android:id="@+id/barrier"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:barrierDirection="right"
    app:constraint_referenced_ids="TextView1,TextView2" />

<TextView
    android:id="@+id/TextView3"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:layout_constraintLeft_toRightOf="@+id/barrier" />

Group

Group 可以把多个控件归为一组,方便隐藏或显示一组控件,举个例子:

<TextView
    android:id="@+id/TextView1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />

<TextView
    android:id="@+id/TextView2"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:layout_constraintLeft_toRightOf="@+id/TextView1" />

<TextView
    android:id="@+id/TextView3"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:layout_constraintLeft_toRightOf="@id/TextView2" />

<android.support.constraint.Group
    android:id="@+id/group"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:visibility="invisible"
    app:constraint_referenced_ids="TextView1,TextView3" />

Placeholder

Placeholder 指的是占位符。在 Placeholder 中可使用 setContent 设置另一个控件的 id,使这个控件移动到占位符的位置。举个例子:

<android.support.constraint.Placeholder
    android:id="@+id/placeholder"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:content="@+id/textview"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintTop_toTopOf="parent" />

<TextView
    android:id="@+id/textview"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="#cccccc"
    android:padding="16dp"
    android:text="TextView"
    android:textColor="#000000"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintTop_toTopOf="parent" />

新建一个 Placeholder 约束在屏幕的左上角,新建一个 TextView 约束在屏幕的右上角,在 Placeholder 中设置 app:content="@+id/textview",这时 TextView 会跑到屏幕的左上角。

Guideline

// Guildline 像辅助线一样,在预览的时候帮助你完成布局(不会显示在界面上)。
android:orientation // 垂直vertical,水平horizontal
layout_constraintGuide_begin // 开始位置
layout_constraintGuide_end // 结束位置
layout_constraintGuide_percent // 距离顶部的百分比(orientation = horizontal时则为距离左边)

<android.support.constraint.Guideline
    android:id="@+id/guideline1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    app:layout_constraintGuide_begin="50dp" />

<android.support.constraint.Guideline
    android:id="@+id/guideline2"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    app:layout_constraintGuide_percent="0.5" />

guideline1 为水平辅助线,开始位置是距离顶部 50dp,guideline2 位垂直辅助线,开始位置为屏幕宽的 0.5 (中点位置),效果如下:

2787721870080d070c12e91.webp

8 百分比布局

百分比布局只提供了 PercentFrameLayout 和 PercentRelativeLayout 两个布局。

引入包:

implementation "androidx.percentlayout:percentlayout:1.0.0"

编写布局:

<?xml version="1.0" encoding="utf-8"?>
<androidx.percentlayout.widget.PercentFrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:id="@+id/button1"
        android:layout_gravity="left|top"
        android:text="button 1"
        app:layout_heightPercent="50%"
        app:layout_widthPercent="50%" />

    <Button
        android:id="@+id/button2"
        android:layout_gravity="right|top"
        android:text="button 2"
        app:layout_heightPercent="50%"
        app:layout_widthPercent="50%" />

</androidx.percentlayout.widget.PercentFrameLayout>

9 自定义布局

9.1 引入布局

title.xml

<?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="wrap_content"
    android:background="@drawable/title_bg">

    <Button
        android:id="@+id/title_back"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_margin="5dp"
        android:background="@drawable/back_bg"
        android:text="Back"
        android:textColor="#fff" />

    <TextView
        android:id="@+id/title_text"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_weight="1"
        android:gravity="center"
        android:text="Title Text"
        android:textColor="#fff"
        android:textSize="24sp" />

    <Button
        android:id="@+id/title_edit"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_margin="5dp"
        android:background="@drawable/edit_bg"
        android:text="Edit"
        android:textColor="#fff" />

</LinearLayout>
<?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" >

    <include layout="@layout/title" />
</LinearLayout>

9.2 自定义布局

当我们想要在多个界面引入此布局,并且所引入的布局需要做一些统一的操作,比如 左上角一直是返回上一个 activity,这时候,就不适合引入布局,如果使用引入布局,我们需要在每个新的布局中进行点击事件的监听,我们采用自定义布局。

public class TitleLayout extends LinearLayout {

    public TitleLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        // 将 title 作为此布局的子项
        LayoutInflater.from(context).inflate(R.layout.title, this);
        Button titleBack = (Button) findViewById(R.id.title_back);
        titleBack.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                ((Activity) getContext()).finish();
            }
        });
    }

}
<?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" >

    <com.example.uicustomviews.TitleLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

</LinearLayout>