ConstraintLayout你学会了吗

860 阅读16分钟

大家好!今天第一天来到掘金,很开心能有机会跟大家相遇,今天主要是分享一些ConstrintLayout的使用。说起这个ConstraintLayout,大家肯定都是有所了解的,谷歌推出这玩意已经很久了,可能是由于历史原因吧,发现很多中小型企业使用它的人还不是很多,但是这并不能否认它的优越性,或许是因为大家不愿意去花时间学这个东西,再加上平时用的那些布局写起来多顺手啊,于是乎也就不想费那个劲去学它了。但是,引用一位哲人说过的话:存在即合理,谷歌既然推出来它,那就肯定有它存在的道理,今天你如果肯花时间看完我这整个一长篇,最后你肯定会吧唧吧唧嘴:嗯,真香!

一、ConstraintLayout简介

官方使用指南(中文版):使用 ConstraintLayout 构建自适应界面

先来看一下谷歌官方对它的介绍:

ConstraintLayout 可让您使用扁平视图层次结构(无嵌套视图组)创建复杂的大型布局。它与 RelativeLayout 相似,其中所有的视图均根据同级视图与父布局之间的关系进行布局,但其灵活性要高于 RelativeLayout,并且更易于与 Android Studio 的布局编辑器配合使用。

ConstraintLayout 的所有功能均可直接通过布局编辑器的可视化工具来使用,因为布局 API 和布局编辑器是专为彼此构建的。 因此,您完全可以使用 ConstraintLayout 通过拖放的形式(而非修改 XML)来构建布局。

ConstraintLayout中文译为“约束布局”,AndroidStudio从2.3开始默认的布局已经更改为约束布局,初学者可以简单的就把它理解为一个“升级版”的相对布局,由于大家玩相对布局都已经玩的很6了,所以完全不用担心,对于约束布局你上手的速度肯定是相当快的!

约束布局功能非常强大,但是它最强大最核心的优势是在于它可以让你的布局“扁平化”,简而言之就是它可以极大程度的减少布局的层级,说到这里敏感的人肯定立马就能想到这句话的言外之意就是“性能优化”,没错,Android性能优化的其中一个方向“布局优化”咱们就可以使用约束布局来替代传统布局实现复杂的界面。

OK,在我们对约束布局有了一个比较详细的了解之后,接下来要做的就是来看看它究竟是如何使用的,通过实际的使用来直观的感受它能够减少布局层级嵌套的含义所在。

二、ConstraintLayout使用

2.1、添加依赖

在使用ConstraintLayout之前,我们需要首先在build.gradle文件中添加依赖:

dependencies {
    implementation "androidx.constraintlayout:constraintlayout:2.0.0"
}

然后我们在布局文件中使用ConstraintLayout,在它的内部先来添加一个TextView,并且我们给它设置了一个背景,让它距离顶部20dp:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
 
    <TextView
        android:layout_width="200dp"
        android:layout_height="200dp"
        android:layout_marginTop="20dp"
        android:background="@color/colorPrimary" />
 
</androidx.constraintlayout.widget.ConstraintLayout>

运行结果如下:你会发现它是位于左上角的,并且并没有距离上方20dp,这是为啥呢? 1.png 当你直接这样写的时候,你的xml文件中TextView控件下方会标红,查看警告信息之后它会告诉你缺少约束,这是啥意思啊?😜,不知道的时候看官方文档啊,来看下图:

2.png 看完文档你就知道了,使用约束布局啊必须要在水平方向和垂直方向上各自至少有一个约束条件,并且像上面代码中那样什么约束条件都不加的话默认是在屏幕的左上角的,并且你设置的margin也是无效的,所以接下来我们就需要正式的了解一下约束条件该如何写喽!

2.2、约束布局使用详解

2.2.1、基本定位

在约束布局中,所有的元素(包括外层的ConstraintLayout和内部子控件)都有上、下、左、右四个方向,在这四个方向上都可以使用约束条件,举个栗子:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto">
 
    <TextView
        android:id="@+id/text"
        android:layout_width="match_parent"
        android:layout_height="45dp"
        android:text="我是美女"
        android:gravity="center"
        android:textSize="18sp"
        android:textColor="@color/white"
        android:background="@color/colorPrimary"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"/>
 
    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/zly"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/text"
        android:layout_marginTop="10dp"/>
 
</androidx.constraintlayout.widget.ConstraintLayout>

结果如下图所示:

3.png 嗯,我们家颖宝真美!回到正题哈,上面的代码中咱们就是使用了约束布局之后做成了图中的效果,仔细看代码,你会发现这个约束条件有点长啊,不信你看:app:layout_constraintStart_toStartOf="parent" 或者 app:layout_constraintTop_toBottomOf="@+id/text",长的还有点像以前的相对布局,我来简单解释一下:

这里布局的约束条件有3部分,一般情况下“layout_”这一部分是固定的,所以我们可以把约束条件看成由后面两部分组成,前半部分表示的是需要建立约束的控件自身的方向比如:constraintTop表示自身上方需要约束,后半部分表示的是约束条件的目标控件的方向比如:toBottomOf表示id为text的控件的下方,那么连起来就是自身顶部位于TextView的下方。另:如果是相对于整个的父布局,则“=”等号后面赋的值为“parent”,如果是相对于其他兄弟控件,则后面是其他控件的id。

通过上面的解释,我相信你已经看懂了约束布局中基本的控件定位该如何写了,下面咱们接着来看居中操作。

2.2.2、居中

在约束布局中设置居中实际上是很灵活的,它不像过去Android五大布局中有gravity或者centerInParent等等类似的很直接的api,它是需要你稍微动一下脑子思考的。举个栗子:比如你想把一张图片横向居中,没有对应的api,就让你添加约束你会怎么尝试?思考一下,我们让图片左侧跟父容器的左侧添加上约束,此时图片会跑到左边对吧,那如果咱们再让图片的右侧跟父容器的右侧也添加上约束呢,它是不是要往右边去,然后你就想了,就好像图片上栓了一根长绳,父容器左右两边各有两个人在往各自的方向上拉,你也拉我也拉大家力道又都一样,可不就给它扯到中间去了吗?😜 嘿嘿,下面就直接来看如下几种居中的实现吧:

  1. 居中于父容器
<!--连起来用就是整体居中-->
//水平方向居中
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
//垂直方向居中
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
  1. 水平方向居中于某个控件
app:layout_constraintStart_toStartOf="@id/widget"
app:layout_constraintEnd_toEndOf="@id/widget"
  1. 垂直方向居中于某个控件
app:layout_constraintTop_toTopOf="@id/widget"
app:layout_constraintBottom_toBottomOf="@id/widget"
  1. A控件沿着B控件的某条边均分 比如:B的下边处在A的正中间
app:layout_constraintTop_toBottomOf="@id/BWidget"
app:layout_constraintBottom_toBottomOf="@id/BWidget"

针对这种的我们来写个例子,不然的话可能不太好理解:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto">
 
    <TextView
        android:id="@+id/text"
        android:layout_width="match_parent"
        android:layout_height="45dp"
        android:text="个人中心"
        android:gravity="center"
        android:textSize="18sp"
        android:textColor="@color/white"
        android:background="@color/colorPrimary"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"/>
 
    <ImageView
        android:id="@+id/mBackground"
        android:layout_width="match_parent"
        android:layout_height="180dp"
        android:src="@drawable/bg"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        android:scaleType="fitXY"
        app:layout_constraintTop_toBottomOf="@id/text"/>
    
    <ImageView
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:src="@drawable/avatar"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toBottomOf="@id/mBackground"
        app:layout_constraintBottom_toBottomOf="@id/mBackground"/>
        
</androidx.constraintlayout.widget.ConstraintLayout>

4.png 头像的垂直方向居中于背景的下边,就是这样一种效果。

2.2.3、充满约束(填充)

当我们在某个方向设置完了约束条件之后,如果把对应方向的宽度或者是高度改为了0dp,那么对应方向的值则会在该约束条件下填满:

//水平方向上填充父容器 match_constraint 
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:layout_width="0dp"

举个栗子看的更直观点:

<?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="match_parent"
    android:layout_height="match_parent">
 
    <TextView
        android:id="@+id/text"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:background="@color/colorPrimary"
        android:gravity="center"
        android:text="横向竖向都填充父容器"
        android:textColor="@color/white"
        android:textSize="18sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
 
</androidx.constraintlayout.widget.ConstraintLayout>

结果如下所示:TextView的横向和竖向都设置的0dp,都填充了父容器:

1.png

2.2.4、权重

只有当水平方向或者垂直方向上是充满约束即0dp时,权重才有效:

<!--TextView1-->
android:layout_width="0dp"
app:layout_constraintHorizontal_weight="2"
<!--TextView2-->
android:layout_width="0dp"
app:layout_constraintHorizontal_weight="1"

举个栗子:

<?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="match_parent"
    android:layout_height="match_parent">
 
    <TextView
        android:id="@+id/text1"
        android:layout_width="0dp"
        android:layout_height="45dp"
        android:background="@color/colorPrimary"
        android:gravity="center"
        android:text="Textview1"
        android:textColor="@color/white"
        android:textSize="18sp"
        app:layout_constraintEnd_toStartOf="@id/text2"
        app:layout_constraintHorizontal_weight="2"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
 
    <TextView
        android:id="@+id/text2"
        android:layout_width="0dp"
        android:layout_height="45dp"
        android:background="@color/colorLight"
        android:gravity="center"
        android:text="Textview2"
        android:textColor="@color/white"
        android:textSize="18sp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_weight="1"
        app:layout_constraintStart_toEndOf="@id/text1"
        app:layout_constraintTop_toTopOf="parent" />
 
</androidx.constraintlayout.widget.ConstraintLayout>

结果如下:

2.png

2.2.5、文字基准线对齐

app:layout_constraintBaseline_toBaselineOf

<?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="match_parent"
    android:layout_height="match_parent">
 
    <TextView
        android:id="@+id/text1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="80"
        android:textColor="#000"
        android:textSize="100sp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
 
    <TextView
        android:id="@+id/text2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="%"
        android:textColor="#000"
        android:textSize="50sp"
        app:layout_constraintBaseline_toBaselineOf="@id/text1"
        app:layout_constraintStart_toEndOf="@id/text1" />
 
</androidx.constraintlayout.widget.ConstraintLayout>

3.png

2.2.6、角度定位

角度定位需要指定三个属性:圆心、半径和角度,其中需要注意的是,这里的角度和Canvas绘制的那个角度有所不同,它是从正上方的顺时针方向开始的:

app:layout_constraintCircle="@id/view"
app:layout_constraintCircleAngle="45"
app:layout_constraintCircleRadius="90dp"

举个栗子:

<?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">
 
    <ImageView
        android:id="@+id/sun"
        android:layout_width="200dp"
        android:layout_height="200dp"
        android:src="@drawable/sun"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
 
    <ImageView
        android:layout_width="80dp"
        android:layout_height="80dp"
        android:src="@drawable/earth"
        app:layout_constraintCircle="@id/sun"
        app:layout_constraintCircleAngle="30"
        app:layout_constraintCircleRadius="250dp"
        tools:ignore="MissingConstraints" />
 
</androidx.constraintlayout.widget.ConstraintLayout>

结果如下图所示:

4.png

2.2.7、约束限制

限制控件大小不会超过约束范围:

app:layout_constrainedWidth="true"
app:layout_constrainedHeight="true

来看代码:当宽度或者高度为wrap_content时,如果使用了上述两个属性,那么会在对应的水平或者垂直方向上限制控件的大小不能超过约束条件的范围大小,如下图所示,右侧文本高度限制最大和背景文本控件高度一致,超出的文字也无法显示了,下方文本控件同理最大宽度限制为和背景文本控件的宽度一致。

<?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">
 
    <TextView
        android:id="@+id/beauty"
        android:layout_width="200dp"
        android:layout_height="200dp"
        android:layout_margin="30dp"
        android:background="@color/colorAccent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
 
    <TextView
        android:layout_width="100dp"
        android:layout_height="wrap_content"
        android:layout_marginLeft="10dp"
        android:text="测试测试测是吉利金刚捡垃圾了几个辣椒酱辣椒嘎啦嘎啦吉利金刚结案率伽古拉简历给了感觉拉拉呱吉利金刚啦简历给叫了个"
        android:textSize="20sp"
        app:layout_constrainedHeight="true"
        app:layout_constraintBottom_toBottomOf="@id/beauty"
        app:layout_constraintStart_toEndOf="@id/beauty"
        app:layout_constraintTop_toTopOf="@id/beauty" />
 
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="15dp"
        android:text="我就感觉垃圾路公交拉工具类就啊两个吉利金刚拉据了解"
        android:textSize="20sp"
        app:layout_constrainedWidth="true"
        app:layout_constraintEnd_toEndOf="@id/beauty"
        app:layout_constraintStart_toStartOf="@id/beauty"
        app:layout_constraintTop_toBottomOf="@id/beauty" />
 
</androidx.constraintlayout.widget.ConstraintLayout>

5.png

2.2.8、偏向

控制控件在水平方向或者垂直方向的位置偏向,偏向值的范围是0-1:

app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintVertical_bias="0.5"

举个栗子:代码如下,左侧放置一个图片,图片右侧放置一个文本,给文本添加约束条件:文本左侧约束在图片的右侧,文本右侧约束在父容器右侧,上下位置居于图片中间,并且限制文本宽度不超过横向的约束范围,此时文本是随着宽度不同而位置不同的,默认居于右侧空白位置中间:

<?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="match_parent"
    android:layout_height="match_parent">
 
    <ImageView
        android:id="@+id/beauty"
        android:layout_width="80dp"
        android:layout_height="80dp"
        android:layout_margin="10dp"
        android:src="@drawable/avatar"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
 
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="10dp"
        android:text="我是测试文本"
        android:textSize="16sp"
        app:layout_constrainedWidth="true"
        app:layout_constraintBottom_toBottomOf="@id/beauty"
        app:layout_constraintStart_toEndOf="@id/beauty"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="@id/beauty"
        android:layout_marginRight="10dp" />
 
</androidx.constraintlayout.widget.ConstraintLayout>

6.png 7.png 可以看到文本较长的时候显示的还是挺美观的,但是当文本字数较少时,这个效果就不是我们想要的了,所以我们此时需要给它加上偏向约束:

这里我给它添加了水平方向的偏向约束,让它靠左显示:app:layout_constraintHorizontal_bias="0.0",结果就很好啦:

8.png

2.2.9、约束可见性处理

控制依赖的约束条件控件隐藏时的间距,不隐藏时此属性无效:

app:layout_goneMarginStart="10dp"

举个栗子:比如这里有水平排列着两个控件一个文本一个图片,在某些业务逻辑下可能需要控制文本的显示和隐藏,当文本显示的时候二者之间不需要有间隔,当文本隐藏的时候图片需要和父容器的左侧有一定的间隔,这种情况就可以使用上面的这行代码了:

<?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="match_parent"
    android:layout_height="match_parent">
 
    <TextView
        android:id="@+id/text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="10dp"
        android:text="我是测试文本"
        android:textSize="20sp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:visibility="gone"/>
 
    <ImageView
        android:layout_width="30dp"
        android:layout_height="30dp"
        android:src="@drawable/icon_home"
        app:layout_constraintStart_toEndOf="@id/text"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_goneMarginStart="10dp" />
 
</androidx.constraintlayout.widget.ConstraintLayout>

9.png 10.png 2.2.10、约束链 在约束链上的第⼀个控件上加上chainStyle,可以⽤来改变⼀组控件的布局⽅式 ,约束链属性分为3种:packed(打包)、spread(扩散)、spread_inside(内部扩散),默认属性是spread,一般用的比较多的是packed,比如我们可以设置垂直⽅向packed,将两个控件合二为一:

app:layout_constraintVertical_chainStyle="packed"

举个栗子:这里我们有一个图片和一个文本,这二者是互相约束的,图片的下方约束到文本的上方,文本的上方约束到图片的下方,文本的左右约束到图片的左右,图片的上方和文本的下方则是约束到父容器的上方和下方,这样就使得他们二者在父容器的空间内被平均分配了,如下图所示:

<?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="match_parent"
    android:layout_height="match_parent">
 
 
    <ImageView
        android:id="@+id/avatar"
        android:layout_width="80dp"
        android:layout_height="80dp"
        android:src="@drawable/avatar"
        app:layout_constraintBottom_toTopOf="@id/text"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
 
    <TextView
        android:id="@+id/text"
        android:layout_width="300dp"
        android:layout_height="200dp"
        android:layout_marginLeft="10dp"
        android:background="@color/colorLight"
        android:gravity="center"
        android:text="我是测试文本"
        android:textSize="20sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="@id/avatar"
        app:layout_constraintStart_toStartOf="@id/avatar"
        app:layout_constraintTop_toBottomOf="@id/avatar" />
 
</androidx.constraintlayout.widget.ConstraintLayout>

11.png 此时需求变更了,需要让图片文本一起整体居中,那么该怎么做呢?使用约束布局就非常简单了,你也不用再在外层嵌套布局了,直接在垂直方向上第一个控件,也就是这里的ImageView上加上一行代码即可搞定,设置垂直方向上的约束链风格为打包packed即可:app:layout_constraintVertical_chainStyle="packed"

12.png 当你设置为打包模式后,同时它还支持偏向设置,比如这里我们再在ImageView上将整体位置调整到垂直方向上20%的地方:app:layout_constraintVertical_bias="0.2"

13.png 2.2.11、宽高比

app:layout_constraintDimensionRatio="16:9"

使用这个属性的前提是宽和高⾄少有⼀个⽅向的值为match_constraint,即:0dp,默认情况下都是宽高比,然后根据另外⼀条边和⽐例算出match_constraint的值,x:y默认表示的就是width:height。

比如下面我们给图片设置它的宽高比为3:4,这里指定了宽为200dp,高为match_constraint,那么它会自动计算高为200/3x4=266.7dp:

<?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="match_parent"
    android:layout_height="match_parent">
 
    <ImageView
        android:layout_width="200dp"
        android:layout_height="0dp"
        android:scaleType="fitXY"
        android:src="@drawable/zly"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintDimensionRatio="3:4"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
 
</androidx.constraintlayout.widget.ConstraintLayout>

1.png 如果宽是0dp,⾼是200dp,ratio 是 2:1 默认情况下是宽是400dp,但是我们可以指定被约束的边是height,那么宽度就是100dp;如果⾼是0dp,宽是200 dp,ratio 是 2:1 默认情况下是⾼是100dp,但是我们指定被约束的边是width,那么⾼度为400dp,(这种指定不推荐使用因为它有点绕)这里以高为0dp为例来看下效果,有个印象即可:

<?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="match_parent"
    android:layout_height="match_parent">
 
    <ImageView
        android:layout_width="200dp"
        android:layout_height="0dp"
        android:scaleType="fitXY"
        android:src="@drawable/zly"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintDimensionRatio="W,2:1"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
 
</androidx.constraintlayout.widget.ConstraintLayout>

2.png 如果宽和高都是0dp,那么你需要指定哪一条边是通过计算得到的,意思也就是没有指定的那一条边则总是充满约束的,比如我们修改一下上面的代码,指定H高通过计算得到,并且修改宽高比为2:1,因为这样看效果比较直观一些:

<?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="match_parent"
    android:layout_height="match_parent">
 
    <ImageView
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:scaleType="fitXY"
        android:src="@drawable/zly"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintDimensionRatio="H,2:1"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
 
</androidx.constraintlayout.widget.ConstraintLayout>

3.png 2.2.12、百分比布局 它需要水平或者垂直⽅向上的值为match_constraint才有效,百分⽐的值是相对于整个parent的百分⽐,⽽不是约束区域的百分⽐,比如宽度是父容器的50%:

android:layout_width="0dp"
app:layout_constraintWidth_percent="0.5"

简单的举个栗子:

<?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="match_parent"
    android:layout_height="match_parent">
 
    <ImageView
        android:id="@+id/beauty"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:scaleType="fitXY"
        android:src="@drawable/zly"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintWidth_percent="0.3" />
 
    <ImageView
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:scaleType="fitXY"
        android:src="@drawable/zly"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintWidth_percent="0.6" />
 
</androidx.constraintlayout.widget.ConstraintLayout>

4.png 百分比布局一般是用来做屏幕适配的,直接在约束布局里面用的并不多。

三、辅助控件

3.1、GuideLine

在约束布局中我们实现百分比的效果很多情况下都是使用这个专门的控件GuideLine,它是用来设置辅助线,以辅助线的位置来做百分比:

  • 设置辅助线的⽅向 android:orientation="vertical"
  • 设置辅助线的位置,根据⽅向不同
  1. 距离左侧或上侧的距离 layout_constraintGuide_begin
  2. 距离右侧或下侧的距离 layout_constraintGuide_end
  3. 百分⽐ layout_constraintGuide_percent 我们来举个实际的例子:
<?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="match_parent"
    android:layout_height="match_parent">
 
    <androidx.constraintlayout.widget.Guideline
        android:id="@+id/guideline"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        app:layout_constraintGuide_begin="90dp" />
 
    <TextView
        android:id="@+id/mUserKey"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="50dp"
        android:text="用户名:"
        android:textColor="@color/colorLight"
        android:textSize="18sp"
        app:layout_constraintEnd_toEndOf="@id/guideline"
        app:layout_constraintTop_toTopOf="parent" />
 
    <EditText
        android:id="@+id/mUserValue"
        android:layout_width="200dp"
        android:layout_height="wrap_content"
        android:layout_marginLeft="10dp"
        android:background="@color/colorLight"
        android:hint="请输入用户名"
        android:textColorHint="#fff"
        app:layout_constraintBottom_toBottomOf="@id/mUserKey"
        app:layout_constraintStart_toEndOf="@id/mUserKey"
        app:layout_constraintTop_toTopOf="@id/mUserKey" />
</androidx.constraintlayout.widget.ConstraintLayout>

5.png 6.png 左侧图片是我截取的AndroidStudio编写XML文件时的Design面板,可以看到辅助线是竖直方向的,并且起始位置是在距离左侧90dp的位置,和我们代码中设置的是一致的,当然你可以自行选择使用dp值还是百分比进行辅助线的定位。

3.2、Group

通过 constraint_referenced_ids 使⽤引用控件id的⽅式来避免布局嵌套,它只能为⼀组控件统⼀设置setVisibility,即可见性,每个控件的点击事件是不能统一处理的,需要你自己来做:

举个栗子:通过点击按钮mBtn来一次性隐藏你想要隐藏的所有文本控件:text1,text2,text3:

<?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="match_parent"
    android:layout_height="match_parent">
 
    <TextView
        android:id="@+id/mBtn"
        android:layout_width="100dp"
        android:layout_height="50dp"
        android:layout_marginTop="50dp"
        android:background="@color/colorLight"
        android:gravity="center"
        android:onClick="clickButton"
        android:text="点击隐藏"
        android:textColor="#fff"
        android:textSize="18sp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
 
    <androidx.constraintlayout.widget.Group
        android:id="@+id/mGroup"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:constraint_referenced_ids="text1,text2,text3" />
 
    <TextView
        android:id="@+id/text1"
        android:layout_width="100dp"
        android:layout_height="50dp"
        android:layout_marginTop="50dp"
        android:background="@color/colorLight"
        android:gravity="center"
        android:text="文本一"
        android:textColor="#fff"
        android:textSize="18sp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/mBtn" />
 
    <TextView
        android:id="@+id/text2"
        android:layout_width="100dp"
        android:layout_height="50dp"
        android:layout_marginTop="50dp"
        android:background="@color/colorLight"
        android:gravity="center"
        android:text="文本二"
        android:textColor="#fff"
        android:textSize="18sp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/mBtn" />
 
    <TextView
        android:id="@+id/text3"
        android:layout_width="100dp"
        android:layout_height="50dp"
        android:layout_marginTop="50dp"
        android:background="@color/colorLight"
        android:gravity="center"
        android:text="文本三"
        android:textColor="#fff"
        android:textSize="18sp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toBottomOf="@id/mBtn" />
    
</androidx.constraintlayout.widget.ConstraintLayout>
public class ConstraintLayoutTestActivity extends AppCompatActivity {
    private boolean flag = true;
 
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_constraint_layout);
    }
 
    public void clickButton(View view) {
        if (flag) {
            findViewById(R.id.mGroup).setVisibility(View.GONE);
            flag = false;
        } else {
            findViewById(R.id.mGroup).setVisibility(View.VISIBLE);
            flag = true;
        }
    }
}

结果如下所示:

7.gif

3.3、Layer

它和 Group 类似,通过引⽤id的⽅式来避免布局嵌套,可以为⼀组控件统⼀设置旋转、缩放、位移等:

<?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">
 
    <TextView
        android:id="@+id/mBtn"
        android:layout_width="100dp"
        android:layout_height="50dp"
        android:layout_marginTop="50dp"
        android:background="@color/colorLight"
        android:gravity="center"
        android:onClick="clickButton"
        android:text="点击变换"
        android:textColor="#fff"
        android:textSize="18sp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
 
    <androidx.constraintlayout.helper.widget.Layer
        android:id="@+id/mLayer"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:constraint_referenced_ids="text1,text2,text3"
        tools:ignore="MissingConstraints" />
 
    <TextView
        android:id="@+id/text1"
        android:layout_width="100dp"
        android:layout_height="50dp"
        android:layout_marginTop="50dp"
        android:background="@color/colorLight"
        android:gravity="center"
        android:text="文本一"
        android:textColor="#fff"
        android:textSize="18sp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/mBtn" />
 
    <TextView
        android:id="@+id/text2"
        android:layout_width="100dp"
        android:layout_height="50dp"
        android:layout_marginTop="50dp"
        android:background="@color/colorLight"
        android:gravity="center"
        android:text="文本二"
        android:textColor="#fff"
        android:textSize="18sp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/mBtn" />
 
    <TextView
        android:id="@+id/text3"
        android:layout_width="100dp"
        android:layout_height="50dp"
        android:layout_marginTop="50dp"
        android:background="@color/colorLight"
        android:gravity="center"
        android:text="文本三"
        android:textColor="#fff"
        android:textSize="18sp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toBottomOf="@id/mBtn" />
 
</androidx.constraintlayout.widget.ConstraintLayout>
public class ConstraintLayoutTestActivity extends AppCompatActivity {
 
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_constraint_layout);
    }
 
    public void clickButton(View view) {
        findViewById(R.id.mLayer).setRotation(45f);
        findViewById(R.id.mLayer).setScaleY(2f);
    }
}

效果如下:

8.gif

3.4、Barrier

通过设置⼀组控件的某个⽅向的屏障,来避免布局嵌套 。

举个栗子:

<?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">
 
    <TextView
        android:id="@+id/text1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@color/colorLight"
        android:gravity="center"
        android:onClick="clickButton"
        android:text="我是测试文本文本"
        android:textColor="#fff"
        android:textSize="30sp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
 
    <ImageView
        android:id="@+id/image1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@mipmap/ic_launcher"
        app:layout_constraintStart_toEndOf="@id/text1"
        app:layout_constraintTop_toTopOf="@id/text1"/>
 
    <TextView
        android:id="@+id/text2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="50dp"
        android:background="@color/colorLight"
        android:gravity="center"
        android:text="测试文本"
        android:textColor="#fff"
        android:textSize="30sp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/text1" />
 
    <ImageView
        android:id="@+id/image2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@mipmap/ic_launcher"
        app:layout_constraintStart_toEndOf="@id/text2"
        app:layout_constraintTop_toTopOf="@id/text2"/>
 
</androidx.constraintlayout.widget.ConstraintLayout>

9.png 比如现在有两行排列的控件,每一行都是一个文本控件一个图片控件,右侧的图片约束在左侧的文本上,如果此时有个需求让你把右侧的图片在垂直方向上对齐,该怎么做呢?你会说那还不简单吗,我把下面图片的左边约束在上方图片的左边不就行了嘛,给image2控件添加一行代码:app:layout_constraintStart_toStartOf="@id/image1"

10.png 哇,还真的可以啊!但是,这样写靠谱吗?来思考一下,假设文本控件上的内容都是取自服务器返回的数据,文本内容字数肯定是不固定的,如果变成了上面的文本字数少下面的文本字数多,嘿嘿,会有啥意想不到的效果呢? 11.png 嗯,图片倒是对的很齐啊,就是有点不太想看,这显然不对了,下方的文本都被图片挡住了个鬼的,所以不能这样搞哦,那么此时咱们的屏障就派上用场了,来看代码:

<?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="match_parent"
    android:layout_height="match_parent">
 
    <androidx.constraintlayout.widget.Barrier
        android:id="@+id/barrier"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:barrierDirection="end"
        app:constraint_referenced_ids="text1,text2" />
 
    <TextView
        android:id="@+id/text1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@color/colorLight"
        android:gravity="center"
        android:onClick="clickButton"
        android:text="测试文本"
        android:textColor="#fff"
        android:textSize="26sp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
 
    <ImageView
        android:id="@+id/image1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@mipmap/ic_launcher"
        app:layout_constraintStart_toEndOf="@id/barrier"
        app:layout_constraintTop_toTopOf="@id/text1" />
 
    <TextView
        android:id="@+id/text2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="50dp"
        android:background="@color/colorLight"
        android:gravity="center"
        android:text="我是测试文本测试文本"
        android:textColor="#fff"
        android:textSize="26sp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/text1" />
 
    <ImageView
        android:id="@+id/image2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@mipmap/ic_launcher"
        app:layout_constraintStart_toEndOf="@id/barrier"
        app:layout_constraintTop_toTopOf="@id/text2" />
 
</androidx.constraintlayout.widget.ConstraintLayout>

同样的通过app:constraint_referenced_ids="text1,text2" 这一行代码来设置这一组文本控件的屏障,由于图片是在屏障的右侧,所以方向barrierDirection设置为end,此时,无论谁的文本长都不会影响对齐效果了,它始终会置于最长的文本之后:

12.png 13.png

3.5、Placeholder

占位符,通过setContentId 来将指定控件放到占位符的位置。这个应该很好理解,就是起到一个占位的作用,在你需要的时候把对应的控件放到占位符的位置上。

来举个栗子看看吧:这里上方放置了一个占位符,下面放了四个控件,点击每个控件,把对应控件放到占位符的位置上:

<?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="match_parent"
    android:layout_height="match_parent">
 
    <androidx.constraintlayout.widget.Placeholder
        android:id="@+id/placeholder"
        android:layout_width="48dp"
        android:layout_height="48dp"
        android:layout_marginTop="28dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
 
    <ImageView
        android:id="@+id/image1"
        android:layout_width="48dp"
        android:layout_height="48dp"
        android:onClick="onClick"
        android:src="@drawable/pack_red"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toStartOf="@id/image2"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
 
    <ImageView
        android:id="@+id/image2"
        android:layout_width="48dp"
        android:layout_height="48dp"
        android:onClick="onClick"
        android:src="@drawable/pack_yellow"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toStartOf="@id/image3"
        app:layout_constraintStart_toEndOf="@id/image1"
        app:layout_constraintTop_toTopOf="parent" />
 
    <ImageView
        android:id="@+id/image3"
        android:layout_width="48dp"
        android:layout_height="48dp"
        android:onClick="onClick"
        android:src="@drawable/pack_blue"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toStartOf="@id/image4"
        app:layout_constraintStart_toEndOf="@id/image2"
        app:layout_constraintTop_toTopOf="parent" />
 
    <ImageView
        android:id="@+id/image4"
        android:layout_width="48dp"
        android:layout_height="48dp"
        android:onClick="onClick"
        android:src="@drawable/pack_purple"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@id/image3"
        app:layout_constraintTop_toTopOf="parent" />
 
</androidx.constraintlayout.widget.ConstraintLayout>

在Java代码中添加点击事件:

public class ConstraintLayoutTestActivity extends AppCompatActivity {
 
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_constraint_layout);
    }
 
    public void onClick(View view) {
        ((Placeholder) findViewById(R.id.placeholder)).setContentId(view.getId());
    }
}

最后效果如下图所示,其实也很简单:

14.gif

3.6、Flow

Flow英文意为流,它同样的也是可以通过引⽤的⽅式来避免布局嵌套,最直观的理解就是可以做成网格的效果,比如横向或者纵向排列的布局。

举个栗子:比如我这里有六张图片,原本都是重叠放在屏幕的左边的,如下图所示:

15.png 现在我在布局文件中添加一个Flow控件,同时你还可以设置排列方向是水平方向还是垂直方向,并且还可以设置各个方向的间距:

17.png 18.png 并且水平方向时我们还可以设置第一个约束链的样式,使用flow_wrapMode属性来设置,值分为3种:chain(链式)、aligned(对齐)、none(默认),我们来实际写一下吧:

<?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="match_parent"
    android:layout_height="match_parent">
 
    <androidx.constraintlayout.helper.widget.Flow
        android:id="@+id/flow"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginLeft="20dp"
        android:layout_marginTop="16dp"
        android:orientation="horizontal"
        app:constraint_referenced_ids="image1,image2,image3,image4,image5,image6"
        app:flow_horizontalGap="20dp"
        app:flow_verticalGap="10dp"
        app:flow_wrapMode="chain"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
 
    <ImageView
        android:id="@+id/image1"
        android:layout_width="88dp"
        android:layout_height="88dp"
        android:onClick="onClick"
        android:src="@drawable/pack_red"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
 
    <ImageView
        android:id="@+id/image2"
        android:layout_width="88dp"
        android:layout_height="88dp"
        android:onClick="onClick"
        android:src="@drawable/pack_yellow"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
 
    <ImageView
        android:id="@+id/image3"
        android:layout_width="88dp"
        android:layout_height="88dp"
        android:onClick="onClick"
        android:src="@drawable/pack_blue"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
 
    <ImageView
        android:id="@+id/image4"
        android:layout_width="88dp"
        android:layout_height="88dp"
        android:onClick="onClick"
        android:src="@drawable/pack_purple"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
 
    <ImageView
        android:id="@+id/image5"
        android:layout_width="88dp"
        android:layout_height="88dp"
        android:onClick="onClick"
        android:src="@drawable/pack_red"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
 
    <ImageView
        android:id="@+id/image6"
        android:layout_width="88dp"
        android:layout_height="88dp"
        android:onClick="onClick"
        android:src="@drawable/pack_yellow"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
 
</androidx.constraintlayout.widget.ConstraintLayout>

16.png

3.7、ConstraintSet

使⽤ ConstraintSet对象可以动态修改布局,为了防⽌布局中存在某些控件可能没有id时会报错,所以我们需要设置isForceId = false。

ConstraintSet对象有很多具体的用法,我今天只简单介绍其中的一种,让大家知道这是个什么玩意,实际使用的过程中有不懂的大家可以再专门查找关于ConstraintSet的资料,也可以参考谷歌的官方文档:ConstraintSet

举个栗子:首先来看这个布局文件:

<?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="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/mLayout">
 
    <TextView
        android:id="@+id/mText"
        android:layout_width="200dp"
        android:layout_height="100dp"
        android:background="@color/colorLight"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        android:textColor="#fff"
        android:text="动态修改我"
        android:gravity="center"
        android:textSize="25sp"/>
 
</androidx.constraintlayout.widget.ConstraintLayout>

它原本的位置效果如下: 19.png 现在我来使用代码动态修改它的约束条件,把它搞到中间去:

public class ConstraintLayoutTestActivity extends AppCompatActivity {
 
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_constraint_layout);
        ConstraintLayout mLayout = findViewById(R.id.mLayout);
        ConstraintSet constraintSet = new ConstraintSet();
        constraintSet.setForceId(false);
        constraintSet.clone(mLayout);
        constraintSet.connect(R.id.mText, ConstraintSet.BOTTOM, ConstraintSet.PARENT_ID, ConstraintSet.BOTTOM);
        constraintSet.applyTo(mLayout);
    }
 
}

程序执行完了之后位置就改变啦:connect()方法的含义是mText的底部要相对于父容器的底部对齐

20.png

3.8、过渡动画

在布局修改之前加上 TransitionManager 来⾃动完成过渡动画: 我们还使用3.7中的代码来举例,首先修改Java文件中的代码,然后将布局文件稍作修改并且添加一个点击事件:

布局文件为:

<?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="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/mLayout">
 
    <TextView
        android:id="@+id/mText"
        android:layout_width="200dp"
        android:layout_height="100dp"
        android:background="@color/colorLight"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        android:textColor="#fff"
        android:text="动态替换"
        android:gravity="center"
        android:onClick="onClick"
        android:textSize="25sp"/>
 
</androidx.constraintlayout.widget.ConstraintLayout>

Java代码为:

public class ConstraintLayoutTestActivity extends AppCompatActivity {
 
    private ConstraintLayout mLayout;
    ConstraintSet constraintSet = new ConstraintSet();
 
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_constraint_layout);
        mLayout = findViewById(R.id.mLayout);
        constraintSet.setForceId(false);
        constraintSet.clone(mLayout);
        constraintSet.connect(R.id.mText, ConstraintSet.BOTTOM, ConstraintSet.PARENT_ID, ConstraintSet.BOTTOM);
    }
 
 
    public void onClick(View view) {
        TransitionManager.beginDelayedTransition(mLayout);
        constraintSet.applyTo(mLayout);
    }
}

结果如下图所示:

21.gif

OK,到这里本篇也就差不多了,文章有点长,写作不易,看完如果对您有些许帮助,烦请给个小心心哦!

祝君:工作顺利!