Android 布局控件之 ConstraintLayout

1,578 阅读13分钟

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

文章目录

介绍

约束布局 ConstraintLayout 是一个 ViewGroup,可以在 Api9 以上的 Android 系统使用它,它的出现主要是为了解决布局嵌套过多的问题,以灵活的方式定位和调整小部件,ConstraintLayout 非常适合使用可视化的方式来编写界面。从 Android Studio 2.3 起,官方的模板默认使用 ConstraintLayout。

ConstraintLayout 官方文档

基本使用

添加依赖

app/build.gradle 文件中添加 ConstraintLayout 的依赖

implementation 'androidx.constraintlayout:constraintlayout:2.0.4'

添加约束

新建一个空项目,Android Studio会自动帮我们创建好一个布局,默认使用 ConstraintLayout

我们将 xml 切换到 Design 模式。现在主操作区域内有两个类似于手机屏幕的界面,左边的是预览界面,右边的是蓝图界面。这两部分都可以用于进行布局编辑工作,区别是左边部分主要用于预览最终的界面效果,右边部分主要用于观察界面内各个控件的约束情况。

如果我们想让 Button 位于布局的右下角,可以进行如下操作:
在这里插入图片描述
首先从左侧的 Palette 区域拖一个 Button 进去,可以看到 Button 的上下左右各有一个圆圈,这圆圈就是用来添加约束的。每个控件的约束都分为垂直和水平两类,一共可以在四个方向上给控件添加约束。我们给 Button 的右边和下边添加了约束,因此 Button 就会将自己定位到布局的右下角了。

如果想让 Button 居中,就需要给它的上下左右都添加约束:
在这里插入图片描述
除此之外,我们还可以使用约束让一个控件相对于另一个控件进行定位。比如说,我们希望再添加一个 Button,让它位于第一个 Button 的正下方,并且间距 84dp:
在这里插入图片描述
删除约束

第一种用于删除一个单独的约束,将鼠标悬浮在某个约束的圆圈上,然后该圆圈会变成同心圆,这个时候单击一下,约束线变成实线后,按下键盘上的 Del 键即可删除
在这里插入图片描述
第二种用于删除某一个控件的所有约束,选中一个控件,右键 -> Clear Constraints of Selection
在这里插入图片描述
第三种用于删除当前界面中的所有约束,点击工具栏中的删除约束图标即可:
在这里插入图片描述

Attributes

选中任意一个控件的时候,在右侧的 Attributes 区域就会出现很多的属性选项
在这里插入图片描述
在这里可以设置当前控件的所有属性,这里不再进行详细介绍,自己操作一下就知道了。下面介绍 Layout 这一部分内容

我们可以看到有一个纵向的轴和一个横向的轴,这两个轴也是用于确定控件的位置的。我们让第一个 Button 居中显示了,其实就是因为这里纵横轴的值都是50。如果调整了纵横轴的比例,那么Button的位置也会随之改变:
在这里插入图片描述
正方形区域,它是用来控制控件大小的。正方形周围输入框能控制边距。中间的符号一共有三种模式可选,每种模式都使用了一种不同的符号表示,点击符号即可进行切换。
在这里插入图片描述
在这里插入图片描述
表示 wrap_content,此时可以使用下列属性来控制最大、最小的高度或宽度:

android:minWidth 最小的宽度
android:minHeight 最小的高度
android:maxWidth 最大的宽度
android:maxHeight 最大的高度

注意!当 ConstraintLayout 为 1.1 版本以下时,使用这些属性需要加上强制约束,如下所示:

app:constrainedWidth=”true”
app:constrainedHeight=”true

在这里插入图片描述
表示固定大小
在这里插入图片描述
表示any size,它有点类似于 match parent,但和 match_parent 并不一样,是属于 ConstraintLayout 中特有的一种大小控制方式,下面我们来重点讲解一下。

首先需要说明,在 ConstraintLayout 中是有 match_parent 的,只不过用的比较少,因为 ConstraintLayout 的一大特点就是为了解决布局嵌套,既然没有了布局嵌套,那么 match_parent 也就没有多大意义了。所以官方不推荐在 ConstraintLayout 中使用 match_parent,可以设置 0dp (MATCH_CONSTRAINT) 配合约束代替 match_parent。

我们将 Button 的宽度指定成any size,它就会自动充满整个布局了:
在这里插入图片描述
这和 match_parent 有什么区别呢?其实最大的区别在于,match_parent 是用于填充满当前控件的父布局,而any_size是用于填充满当前控件的约束规则。举个例子更好理解,如果我们有一个新的 Button,它的其中一个约束是添加到当前这个 Button 上的,那么any_size的效果也会发生改变:

在这里插入图片描述

我们切换到code 模式看下代码中是如何写的

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

    <Button
        android:id="@+id/button10"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="Button"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/button13"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:text="Button"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/button10" />
</androidx.constraintlayout.widget.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

这些属性根据名字就很容易知道它们的意思。

举例:实现以下效果
在这里插入图片描述

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

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

    <TextView
        android:id="@+id/tv2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="TextView2"
        ...
        app:layout_constraintLeft_toRightOf="@+id/tv1" />

    <TextView
        android:id="@+id/tv3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="TextView3"
        ...
        app:layout_constraintTop_toBottomOf="@+id/tv1" />
</androidx.constraintlayout.widget.ConstraintLayout>

layout_constraintLeft_toRightOf

对于一个View的边界界定,官方给了下面这张图:
在这里插入图片描述
一般情况下只是用 layout_constraintLeft_toRightOf 效果是这样的:
在这里插入图片描述
如图所示,两个 TextView 的高度不一致,但是又希望他们文本对齐,这个时候就可以使用 layout_constraintBaseline_toBaselineOf
在这里插入图片描述

<TextView
        android:id="@+id/tv1"
        android:layout_width="wrap_content"
        android:layout_height="40dp"
        android:background="#D8BFD8"
        android:gravity="center"
        android:text="TextView1" />

    <TextView
        android:id="@+id/tv2"
        android:layout_width="wrap_content"
        android:layout_height="20dp"
        android:background="#DDA0DD"
        android:text="TextView2"
        app:layout_constraintBaseline_toBaselineOf="@+id/tv1"
        app:layout_constraintLeft_toRightOf="@+id/tv1" />

角度定位

角度定位指的是可以用一个角度和一个距离来约束两个空间的中心

上面例子中的 TextView2 使用以下3个属性:

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

在这里插入图片描述
TextView2 的中心在TextView1的中心的 120度,距离为 150dp

边距
ConstraintLayout 的边距常用属性如下:

  • android:layout_marginStart
  • android:layout_marginEnd
  • android:layout_marginLeft
  • android:layout_marginTop
  • android:layout_marginRight
  • android:layout_marginBottom

看起来跟别的布局没有什么差别,但实际上控件在 ConstraintLayout 里面要实现 margin ,必须先约束该控件在 ConstraintLayout 里的位置,如果不进行约束,margin 是不生效的:
在这里插入图片描述
如果在别的布局里,tv1 的位置应该是距离边框的左边和上面有一个 10dp 的边距,但是在 ConstraintLayout 里,是不生效的,因为没有约束 tv1 在布局里的位置。正确的写法如下:
在这里插入图片描述
goneMargin

goneMargin 主要用于约束的控件可见性被设置为gone的时候使用的 margin 值,属性如下:

  • layout_goneMarginStart
  • layout_goneMarginEnd
  • layout_goneMarginLeft
  • layout_goneMarginTop
  • layout_goneMarginRight
  • layout_goneMarginBottom

举例:goneMargin 使用
TextView2 的左边约束在 TextView1 的右边,并给 TextView2 设一个app:layout_goneMarginLeft="10dp"

<TextView
        android:id="@+id/tv1"
        android:layout_width="wrap_content"
        android:layout_height="40dp"
        android:background="#D8BFD8"
        android:gravity="center"
        android:text="TextView1" />

    <TextView
        android:id="@+id/tv2"
        android:layout_width="wrap_content"
        android:layout_height="40dp"
        android:background="#D8BFFF"
        android:gravity="center"
        android:text="TextView2"
        app:layout_constraintLeft_toRightOf="@+id/tv1"
        app:layout_goneMarginLeft="10dp" />

效果如图,TextView2 在TextView1 的右边,且没有边距
在这里插入图片描述
这个时候把 TextView1 的可见性设为gone,效果如下:
在这里插入图片描述

可以看到 TextView1 消失后,TextView2 有一个距离左边 10dp 的边距。

居中

开始我们通过视图将一个按钮进行了居中显示,我们切换到 code 模式下看 xml 中是如何写的

<Button
        android:id="@+id/button10"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

同理,水平居中就要在 ConstraintLayout 约束控件的左右为 parent 的左右;垂直居中需在 ConstraintLayout 约束控件的上下为 parent 的上下。

需要 注意 的是 ConstraintLayout 的宽高要设置为match_parent,否则居中不生效

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

偏移

  • layout_constraintHorizontal_bias 水平偏移
  • layout_constraintVertical_bias 垂直偏移

假如要实现水平偏移,需给 TextView1 的layout_constraintHorizontal_bias赋一个范围为 0-1 的值。

假如赋值为 0,则 TextView1 在布局的最左侧。假如赋值为 1,则 TextView1 在布局的最右侧。假如假如赋值为 0.5,则水平居中。假如假如赋值为 0.3,则更倾向于左侧。

垂直偏移同理。

假如layout_constraintHorizontal_bias赋值为 0.3,效果如图:在这里插入图片描述

layout_constraintDimensionRatio 宽高比

当宽或高至少有一个尺寸被设置为 0dp 时,可以通过属性layout_constraintDimensionRatio设置宽高比

<TextView
        android:id="@+id/tv1"
        android:layout_width="0dp"
        android:layout_height="100dp"
        android:background="#D8BFD8"
        android:gravity="center"
        android:text="TextView1"
        app:layout_constraintDimensionRatio="1:1"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent" />

宽设置为 0dp,宽高比设置为 1:1,这个时候 TextView1 是一个正方形:
在这里插入图片描述
除此之外,在设置宽高比的值的时候,还可以在前面加WH,分别指定宽度或高度限制:

app:layout_constraintDimensionRatio="H,2:3"指的是 高:宽=2:3
app:layout_constraintDimensionRatio="W,2:3"指的是 宽:高=2:3

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

在这里插入图片描述
举例:实现以下效果
在这里插入图片描述

     <TextView
        android:id="@+id/tv1"
        android:layout_width="wrap_content"
        android:layout_height="40dp"
        android:background="#DDA0DD"
        android:gravity="center"
        android:text="TextView1"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toLeftOf="@+id/tv2" />

    <TextView
        android:id="@+id/tv2"
        android:layout_width="wrap_content"
        android:layout_height="40dp"
        android:background="#D8BFD8"
        android:gravity="center"
        android:text="TextView2"
        app:layout_constraintLeft_toRightOf="@+id/tv1"
        app:layout_constraintRight_toLeftOf="@+id/tv3" />

    <TextView
        android:id="@+id/tv3"
        android:layout_width="wrap_content"
        android:layout_height="40dp"
        android:background="#FFC0CB"
        android:gravity="center"
        android:text="TextView3"
        app:layout_constraintLeft_toRightOf="@+id/tv2"
        app:layout_constraintRight_toRightOf="parent" />

一条链的第一个控件是这条链的链头,我们可以在链头中设置 layout_constraintHorizontal_chainStyle来改变整条链的样式。chains提供了3种样式,分别是:
在这里插入图片描述

  • spread —— 展开元素 (默认);

    效果如上图

  • spread_inside —— 展开元素,但链的两端贴近 parent;
    在这里插入图片描述

  • packed—— 链的元素将被打包在一起
    在这里插入图片描述
    layout_constraintHorizontal_weight 权重链
    可以留意到上面所用到的 3 个 TextView 宽度都为 wrap_content,如果我们把宽度都设为 0dp,这个时候可以在每个 TextView 中设置横向权重。我们使用layout_constraintHorizontal_weight(constraintVertical 为纵向)来创建一个权重链

    <TextView
        android:id="@+id/tv1"
        android:layout_width="0dp"
        android:layout_height="40dp"
        android:background="#DDA0DD"
        android:gravity="center"
        android:text="TextView1"
        app:layout_constraintHorizontal_weight="1"
        app:layout_constraintHorizontal_chainStyle="packed"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toLeftOf="@+id/tv2" />

    <TextView
        android:id="@+id/tv2"
        android:layout_width="0dp"
        android:layout_height="40dp"
        android:background="#D8BFD8"
        android:gravity="center"
        android:text="TextView2"
        app:layout_constraintHorizontal_weight="2"
        app:layout_constraintLeft_toRightOf="@+id/tv1"
        app:layout_constraintRight_toLeftOf="@+id/tv3" />

    <TextView
        android:id="@+id/tv3"
        android:layout_width="0dp"
        android:layout_height="40dp"
        android:background="#FFC0CB"
        android:gravity="center"
        android:text="TextView3"
        app:layout_constraintHorizontal_weight="3"
        app:layout_constraintLeft_toRightOf="@+id/tv2"
        app:layout_constraintRight_toRightOf="parent" />

在这里插入图片描述

辅助工具

除了 ConstraintLayout 自身属性之外,谷歌还提供了很多辅助布局(只是在布局中起辅助作用,并不会在界面真正显示),来使 ConstraintLayout 的功能更加强大。

Guideline

刚才我们已经实现了让一个按钮居中对齐的功能,如果我们想让两个按钮共同居中对齐该怎么实现呢?

其实这个需求很常见,比如说在应用的登录界面,都会有一个登录按钮和一个注册按钮,不管它们是水平居中也好还是垂直居中也好,但肯定都是两个按钮共同居中的。这就需要用到 Guideline。

现在已经向界面中添加了登录和注册这两个按钮,我们希望让这两个按钮在水平方向上居中显示,在垂直方向上都距离底部 152dp,那么就需要先添加一个垂直方向上的 Guideline。

点击通知栏中的 Guidelines 图标可以添加一个垂直或水平方向上的 Guideline,而Guideline 默认是使用的 dp 尺,我们需要选中 Guideline,并点击最上面的箭头图标将它改成百分比尺,拖动到50%的位置。

在这里插入图片描述
接着登录按钮的右边向 Guideline 添加约束,登录按钮的下面向底部添加约束,并拖动按钮让它距离底部 152dp。然后给注册按钮的左边向 Guideline 添加约束,注册按钮的下面向登录按钮的下面添加约束。这样就实现了让两个按钮在水平方向上居中显示,在垂直方向上都距离底部 152dp 的功能了。
在这里插入图片描述

切换到 code 模式看下 xml 中怎么写的:

<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">


    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="152dp"
        android:text="登录"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toStartOf="@+id/guideline4" />

    <Button
        android:id="@+id/button9"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="注册"
        app:layout_constraintBottom_toBottomOf="@+id/button"
        app:layout_constraintStart_toStartOf="@+id/guideline4" />

    <androidx.constraintlayout.widget.Guideline
        android:id="@+id/guideline4"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        app:layout_constraintGuide_percent="0.5" />

</androidx.constraintlayout.widget.ConstraintLayout>

Guildline 属性:

  • android:orientation 垂直vertical,水平horizontal
  • layout_constraintGuide_begin 开始位置
  • layout_constraintGuide_end 结束位置
  • layout_constraintGuide_percent 距离顶部的百分比(orientation = horizontal时则为距离左边)

自动添加约束

自动添加约束的方式主要有两种,一种叫 Autoconnect,一种叫 Inference,我们先来看第一种。

想要使用 Autoconnect,首先需要在工具栏中将这个功能启用,默认情况是不启用的:
在这里插入图片描述
Autoconnect 可以根据我们拖放控件的状态自动判断应该如何添加约束,比如我们将 Button 放到界面的正中央,那么它的上下左右都会自动地添加上约束:
在这里插入图片描述
不过 Autoconnect 是无法保证百分百准确判断出我们的意图的,如果自动添加的约束并不是你想要的话,还可以在任何时候进行手动修改。总之,可以把它当成一个辅助工具,但不能完全靠它去添加控件的约束。

Inference 也是用于自动添加约束的,但它比 Autoconnect 的功能要更为强大,因为 AutoConnect 只能给当前操作的控件自动添加约束,而 Inference 会给当前界面中的所有元素自动添加约束。因而 Inference 比较适合用来实现复杂度比较高的界面,它可以一键自动生成所有的约束。下面举例说明。

比如界面上现在有两个 TextView,两个 EditText,和两个 Button。
在这里插入图片描述
先将各个控件按照界面设计的位置进行摆放,摆放完成之后点击一下工具栏上的 Infer Constraints 按钮,就能为所有控件自动添加约束了:
在这里插入图片描述
最总效果:
在这里插入图片描述

Group

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

我们用 链 一节的三个 TextView 为例。现在有3个并排的 TextView,用 Group 把 TextView1 和 TextView3 归为一组,再设置这组控件的可见性
在这里插入图片描述
xml 中增加

<androidx.constraintlayout.widget.Group
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:visibility="invisible"
        app:constraint_referenced_ids="tv1,tv3" />

显示结果:
在这里插入图片描述

Placeholder

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

<androidx.constraintlayout.widget.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 会跑到屏幕的左上角。

Barrier

屏障,一个虚拟View。主要解决下面遇到的问题:
在这里插入图片描述
假设有 3 个控件ABC,AB 的宽是不固定的,C 在 AB 的右边,这个时候 C 无论约束在 A 的右边或者 B 的右边都不对。当出现这种情况可以用 Barrier 来解决。 Barrier 可以在多个控件的一侧建立一个屏障
在这里插入图片描述
C 只要约束在 Barrier 的右边就可以了。

<TextView
        android:id="@+id/tv1"
        android:layout_width="100dp"
        android:layout_height="40dp"
        android:background="#DDA0DD"
        android:gravity="center"
        android:text="TextView1" />

    <TextView
        android:id="@+id/tv2"
        android:layout_width="200dp"
        android:layout_height="40dp"
        android:background="#D8BFD8"
        android:gravity="center"
        android:text="TextView2"
        app:layout_constraintTop_toBottomOf="@+id/tv1" />

    <androidx.constraintlayout.widget.Barrier
        android:id="@+id/barrier"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:barrierDirection="right"
        app:constraint_referenced_ids="tv1,tv2" />

    <TextView
        android:id="@+id/tv3"
        android:layout_width="wrap_content"
        android:layout_height="50dp"
        android:background="#FFC0CB"
        android:gravity="center"
        android:text="TextView3"
        app:layout_constraintLeft_toRightOf="@+id/barrier" />

app:constraint_referenced_ids 为屏障引用的控件,可设置多个(用,隔开)

app:barrierDirection为屏障所在的位置,可设置的值有:bottom、end、left、right、start、top
在这里插入图片描述

ConstraintSet 使用,动态修改约束布局

官方文档

以往我们在代码中动态的修改布局中控件的大小、位置以及与其他控件的相对关系时,都需要使用到 LayoutParams,不同的布局有对应的不同的LayoutParams 的子类,使用起来十分繁琐。而 ConstraintLayout 与之搭配的就是 ConstraintSet

1、创建和初始化ConstraintSet

ConstraintSet constraintSet = new ConstraintSet();
//用法1:从ConstraintLayout实例中获取约束集,最常用的用法
constraintSet.clone(mainLayout)//mainLayout为ConstraintLayout
//用法2:从布局中获取约束集
constraintSet.clone(context, R.layout.my_layout)//my_layout.xml的根布局必须是ConstraintLayout
//用法3:从其他约束集中获取约束集
constraintSet.clone(otherConstraintSet)

2、设置组件之间的约束

constraintSet.connect(startID: Int, startSide: Int, endID: Int, endSide: Int, margin: Int)
 
constraintSet.connect(startID: Int, startSide: Int, endID: Int, endSide: Int)

3、可以修改控件尺寸

constrainWidth(int viewId, int width)
constrainHeight(int viewId, int height)
constrainPercentWidth(int viewId, float percent)
constrainPercentHeight(int viewId, float percent)

其他的跟尺寸有关的API还有:

constrainDefaultWidth/constrainDefaultHeight
constrainMaxWidth/constrainMaxHeight
constrainMinWidth/constrainMinHeight
用来设置一些默认、最大最小尺寸,不常用,可以看以下文章展示的例子 RecyclerView 设置最大高度

4、设置动画

TransitionManager.beginDelayedTransition(mainLayout)

5、apply一下使设置生效

constraintSet.applyTo(rootLayout)

举例:ConstraintSet 练习

xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/view_constraintLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="button1"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/button2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="button2"
        app:layout_constraintLeft_toRightOf="@+id/button1"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/operate"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="button3"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>
Button operate = findViewById(R.id.operate);

        ConstraintLayout constraintLayout = findViewById(R.id.view_constraintLayout);
        ConstraintSet constraintSet = new ConstraintSet();
        constraintSet.clone(constraintLayout);

        operate.setOnClickListener(v -> {
            constraintSet.connect(R.id.button2, ConstraintSet.TOP, R.id.button1, ConstraintSet.BOTTOM, dpToPx(this, 40));
            constraintSet.connect(R.id.button2, ConstraintSet.LEFT, ConstraintSet.PARENT_ID, ConstraintSet.LEFT);
            constraintSet.constrainWidth(R.id.button2, ConstraintSet.WRAP_CONTENT);
            constraintSet.constrainHeight(R.id.button2, dpToPx(this, 100));
            TransitionManager.beginDelayedTransition(constraintLayout);
            constraintSet.applyTo(constraintLayout);
        });

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