一、简介
ConstraintLayout在2016 年 Google I/O 中面世,它提供了扁平视图层次结构(无嵌套视图组)来创建复杂的大型布局。因此这个控件的出现主要是为了解决开发中复杂页面的嵌套层级问题。
与 RelativeLayout 相似,其中所有的视图均根据同级视图与父布局之间的关系进行布局,但其灵活性要高于 RelativeLayout,并且更易于与 Android Studio 的布局编辑器配合使用(拖拽方式)。
从 Android Studio 2.3起,创建layout文件默认为ConstraintLayout。
二、了解
虽说Android studio从2.3开始默认支持了ConstraintLayout,但是我们也应当了解下控件的引入流程
1、控件的引入
首先看下这个控件的引入流程,其实很简单和AS中使用三方库依赖方式一样。
// project/build.gradle
repositories {
google()
}
// app/buidl.gradle
dependencies {
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
}
2、AS根布局默认更改
AS2.3开始创建布局文件时默认为constraintlayout,当然若不想使用可以更改:
如果创建布局文件时忘记了修改为x想要的根布局,编译器还提供了修改的功能,如下:
三、常见约束
首先了解下约束规则,ConstraintLayout采用方向约束的方式对控件进行定位,这就要求每个控件都必须至少有两个约束条件:一个水平约束条件,一个垂直约束条件。否则控件默认显示在ConstraintLayout容器的左上角。
前面说了必须保证子View在水平、垂直两个方向都至少有一个约束条件这里我们就实现个“控件在容器右上角”的效果。
可见为AppCompatButton属性添加了两行约束就把控件的位置定位在右上角了。其实核心布局代码就两行:
1、app:layout_constraintRight_toRightOf="parent"表示控制水平方向控件右端与父控件右端对齐
2、app:layout_constraintTop_toTopOf=“parent” 表示控制垂直方向控件顶部与父控件顶部对齐
有的小伙伴可能会来抬杠了,你前面所说“这就要求每个子View控件都必须至少有两个约束条件即一个水平约束条件,一个垂直约束条件。”那么我实现右上角的效果就一个约束就解决了,如下:(打脸????)
emmmm我来解释下原因,还记得约束规则的最后一句话吗?“否则控件默认显示在ConstraintLayout容器的左上角”,这里我们不妨可以思考下为啥默认显示在左上角?
其实若要子控件默认显示在左上角,则水平方向上,子控件的左端要与父控件左端对齐,垂直方向上子控件顶部要与父控件顶部对齐。没错不添加任何约束,子控件默认是具备这两个约束条件的。
这里就解释通了为啥垂直方向上没有设置约束自己的子控件默认具备了顶部对齐,当然编译器也是很智能的,看看控件的红色警告同样可以说明控件是有默认约束的。
1、基本约束
通过上面的栗子引申,我们了解到了两个约束:
//我这个控件的右端与XXX控件右端对齐
app:layout_constraintRight_toRightOf="parent"
//我这个控件的顶端与XXX控件顶端对齐
app:layout_constraintTop_toTopOf="parent"
哎呦这两个约束条件让我不免想起了相对布局:
android:layout_toLeftOf=""
android:layout_toRightOf=""
...
那么我猜约束布局肯定和相对布局一样,一定还提供了其他的类似约束,比着葫芦画瓢大胆猜测下应该还有诸如“我的左侧与xxx控件左侧对齐”、“我的底部与xxx控件底部对齐”等属性。
其实正如我们猜测的一样,约束布局的确提供了类似的属性,由于这些属性是最常见的约束属性,这里我就把他们划分为基本约束来放一块总结了:
//我这个控件的左端与XXX控件左端对齐
app:layout_constraintLeft_toLeftOf=""
//我这个控件的右端与XXX控件右端对齐
app:layout_constraintRight_toRightOf=""
//我这个控件的顶端与XXX控件顶端对齐
app:layout_constraintTop_toTopOf=""
//我这个控件的底端与XXX控件底端对齐
app:layout_constraintBottom_toBottomOf=""
//我这个控件的右端与XXX控件右端对齐
app:layout_constraintRight_toLeftOf=""
//我这个控件的订端与XXX控件底端对齐
app:layout_constraintTop_toBottomOf=""
...
注意:
1、上述的基本约束都是有规律的:
- 水平方向上,我的m端与其他控件n端对齐
- 垂直方向上,我的m端与其他控件n端对齐
2、上述的right/left 可以使用end/start 来替换。
学以致用,来简单实现个居中的栗子吧,其实很好理解,我的上下左右端分别与父控件上下左右端对齐,则我就居中了。
2、基线对齐
如上是开发中常见的场景,假如碰到这个需求时我们可能会首先想到常见的两种设计,即外部包括线性布局或者外部包括相对布局来实现。然而当外部是约束布局时这个需求是很容易实现的仅仅需要两步:
1、通过约束调相对位置 ($ 的起始位置在10结束位置的右面)
2、添加基线对齐的约束($ 指定基线与10的基线对齐)
<?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">
<!-- 基线对齐-->
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="10"
android:textAllCaps="false"
android:textColor="#000000"
android:textSize="50sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="HardcodedText" />
<androidx.appcompat.widget.AppCompatTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="$"
android:textAllCaps="false"
android:textColor="#ff0000"
android:textSize="20sp"
//1、通过约束调相对位置 ($ 的起始位置在10结束位置的右面)
app:layout_constraintLeft_toRightOf="@id/textView"
// 2、添加基线对齐的约束($ 指定基线与10的基线对齐)
app:layout_constraintBaseline_toBaselineOf="@id/textView"
tools:ignore="HardcodedText" />
</androidx.constraintlayout.widget.ConstraintLayout>
可见实现是十分简单的,然而layout_constraintBaseline_toBaselineOf到底该如何理解呢?或许你还会看到类似属性firstBaselineToTopHeight、lastBaselineToBottomHeight接下来我们就举例子看下:
首先来看一个默认效果,也即一个bg为灰色的TextView。
(1)设置firstBaselineToTopHeight=100dp后
注意:这时给TextView设置gravity调整文字位置时是不起作用的。你不妨可设置个gravity试试,效果竟然不居中,还是上图效果。
(2)设置lastBaselineToBottomHeight="100dp"后
(3)layout_constraintBaseline_toBaselineOf
这个如何理解呢?我们就当做lastBaseLine来理解吧,constraintBaseline_toBaselineOf可理解成两控件lastBaseLine 对齐。
疑惑:这里所说的Baseline都是水平方向上的线,那么有垂直方向上的吗?这个自己还不知道,若以后得知结果再回来修改这里填坑。。。。。。
3、角度约束
在开发过程中大家可能碰到这个需求,用户vip头像,也即vip头像右上角约45°有个皇冠图片。
<?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">
// 目标控件
<com.makeramen.roundedimageview.RoundedImageView
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:id="@+id/imageView1"
android:src="@drawable/mei"
android:scaleType="centerCrop"
app:riv_corner_radius="5dp"
app:riv_border_width="2dip"
app:riv_border_color="#333333"
app:riv_mutate_background="true"
app:riv_tile_mode="repeat"
app:riv_oval="true"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/imageView2"
android:layout_width="60dp"
android:layout_height="60dp"
android:src="@drawable/huangguan"
//目标控件
app:layout_constraintCircle="@+id/imageView1"
//相对目标控件的角度(顺时针)
app:layout_constraintCircleAngle="45"
//相对目标控件中心的距离
app:layout_constraintCircleRadius="130dp" />
</androidx.constraintlayout.widget.ConstraintLayout>
4、百分比偏移
百分比偏移很好理解,就是子控件在父控件中相对偏移量。
注意:
1、相对起点为容器左上角。
2、在使用水平偏移或者垂直偏移约束时,控件要具有水平或者垂直方向上的约束。
5、GONE Margin
安卓的View控件提供了padding、margain同样ConstraintLayout也是View也是具有基础view的边距属性的。除此之外ConstraintLayout 还提供了GONE Margin
app:layout_goneMarginBottom="xxxdp"
app:layout_goneMarginEnd="xxxdp"
app:layout_goneMarginLeft="xxxdp"
app:layout_goneMarginRight="xxxdp"
app:layout_goneMarginStart="xxxdp"
app:layout_goneMarginTop="xxxdp"
作用,目标控件VISIABLE、INVISIABLE时,goneMargin不生效。目标控件GONE时,goneMargin生效。
<?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:orientation="horizontal">
<!-- 目标控件,invisible -->
<androidx.appcompat.widget.AppCompatTextView
android:visibility="invisible"
android:text="tv1"
android:textColor="#ffffff"
android:gravity="center"
android:textSize="20sp"
android:id="@+id/tv1"
android:layout_width="50dp"
android:layout_height="50dp"
android:background="#ff0000"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent" />
<androidx.appcompat.widget.AppCompatTextView
android:text="tv2"
android:textColor="#ffffff"
android:gravity="center"
android:textSize="20sp"
android:layout_width="50dp"
android:layout_height="50dp"
android:background="@color/design_default_color_secondary_variant"
app:layout_constraintStart_toEndOf="@id/tv1"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
//margin start 100dp
app:layout_goneMarginStart="100dp"/>
</androidx.constraintlayout.widget.ConstraintLayout>
6、尺寸相关
(1)最大/最小宽高
ConstraintLayout 提供了maxWidth/Height、minWidth/Height属性来限制控件的最大最小宽高,但是这些属性要结合wrap_content来使用才会生效。
举个栗子为控件设置minHeight 时,控件的高度要设置为wrap_content。
android:layout_height="wrap_content"
android:minHeight="100dp"
接下来以maxHeight来理解下:
<?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"
android:orientation="horizontal">
<!-- maxHeight -->
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tv1"
android:layout_width="50dp"
android:layout_height="wrap_content"
android:background="#ff0000"
android:gravity="center"
android:maxHeight="100dp"
android:text="tv1"
android:textColor="#ffffff"
android:textSize="20sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="HardcodedText" />
</androidx.constraintlayout.widget.ConstraintLayout>
const val TAG = "MainActivity"
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.test9)
// 控件初始高
tv1.post {
Log.d(TAG, "defaultHeight:${tv1.height}")
}
// 每次点击控件时 控件文字size变大。由于控件高度wrap_content 则高度自适应变大。
tv1.apply {
setOnClickListener {
textSize += 20
Log.d(TAG, "currentHeight:$height")
}
}
}
}
// 每次观察点击事件发现控件最大高度为100dp,这个是我们xml中设置的上限,生效了。
2021-12-19 20:20:24.277 28059-28059/com.sunnyday.constraintlayout.practice D/MainActivity: defaultHeight:28
2021-12-19 20:20:34.459 28059-28059/com.sunnyday.constraintlayout.practice D/MainActivity: currentHeight:28
2021-12-19 20:20:45.886 28059-28059/com.sunnyday.constraintlayout.practice D/MainActivity: currentHeight:100
2021-12-19 20:20:47.284 28059-28059/com.sunnyday.constraintlayout.practice D/MainActivity: currentHeight:100
(2)0 dp
还记的LinearLayout的权重吗?我们回顾下使用步骤
1、设置layout_width或者layout_height 宽度为0dp
2、设置layout_weight = xxx
ConstraintLayout这个功能和LinearLayout的权重很类似。使用步骤如下:
//这步和LinearLayout一样
1、设置layout_width或者layout_height 宽度为0dp。
//约束宽度,取值有三种。
//约束高度可以使用app:layout_constraintHeight_default="spread|percent|wrap"
2、app:layout_constraintWidth_default="spread|percent|wrap"
可以看到约束的属性值有三种,下面看下这三种值代表的含义
- spread:铺满剩余可用空间。(默认)
可以发现设置宽或者高度为0后,然后进行约束,约束值设置为spread宽度铺满剩余空间。高度300dp居中。
为啥高度没有铺满剩余空间?还记得前面的解释吗?留意下“可用”二字,观察代码发现控件设置了高度约束,最大为300dp。所以这是控件的其他限制,我们不妨可以试试吧这个最大高度去除然后为控件添加margin后控件同样不会铺满全屏。
这里需要强调下 ‘’spread “作为默认值的含义,其实所有的ConstraintLayout子控件都默认具有如下约束,当我们设置 layout_Height = 0dp 或者layout_width = 0dp 时即可使满足的约束生效。
// 所有子控件默认具有这俩属性,属性值默认spread
app:layout_constraintWidth_default="spread"
app:layout_constraintHeight_default="spread"
// 因此上述的截图栗子完全可以删除这两行代码,效果是一样的。如下:
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tv1"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintHeight_max="300dp"
android:background="#ff0000"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="HardcodedText" />
- percent:子控件的宽度或者高度占父控件的百分比
这里需要注意,当约束值设置为percent时要额外配合layout_constraintXXX_percent来食用。
其实使用layout_constraintXXX_percent时,layout_constraintXXX_default= "percent"这个去除也是可以的。
- wrap:根据控件内容进行自适应调整,但不超过约束限制。
如何理解呢?可以理解为和wrap_content属性类似,二者区别是wrap_content会超过约束限制,wrap 不会。
<?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"
android:orientation="horizontal">
<!-- 控件:
android:layout_width="wrap_content"
android:layout_marginStart="100dp"
-->
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tv1"
android:layout_width="wrap_content"
android:layout_height="100dp"
android:background="#ff0000"
android:layout_marginStart="100dp"
android:text="一剑仙人跪、一剑仙人跪、一剑仙人跪、"
android:gravity="center"
android:textColor="#ffffff"
android:textSize="20sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="HardcodedText" />
<!-- 控件:
android:layout_width="0dp"
app:layout_constraintWidth_default= "wrap"
android:layout_marginStart="100dp"
-->
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tv2"
android:layout_width="0dp"
android:layout_height="100dp"
app:layout_constraintWidth_default= "wrap"
android:layout_marginStart="100dp"
android:background="#000000"
android:text="一剑仙人跪、一剑仙人跪、一剑仙人跪、"
android:gravity="center"
android:textColor="#ffffff"
android:textSize="20sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv1"
tools:ignore="HardcodedText" />
</androidx.constraintlayout.widget.ConstraintLayout>
收获:控件宽或高设置wrap_content时,当控件内容足够宽或者高时便会打破margin值。
emmm以前竟然没有留意这个细节。这里先记录下结论,以后探究下。
补充:0dp还可以结合以下属性来食用:
app:layout_constraintWidth_max="" 0dp约束下,宽度最值
app:layout_constraintHeight_max="" 0dp约束下,高度最值
app:layout_constraintWidth_min="" 0dp约束下,宽度最值
app:layout_constraintHeight_min="" 0dp约束下,高度最值
(3)Ratio-宽高比例
通过layout_constraintDimensionRatio=“宽:高” 或者layout_constraintDimensionRatio=“宽/高” 可以设置控件宽高比。食用这个约束的前提条件是控件至少有一个约束维度设置为0dp。
7、Chains(链)
何为链呢?这就要求控件之间在水平或者垂直上具有相互约束如下:
链的形成十分简单,使用基本约束即可,如上图形成的链我们称为“水平链”,所以垂直方向上的链我们就称为“垂直链”有了链后我们就可以使用链相关的约束来操作控件了。相关属性如下:
//水平链约束(注意这个设置给链的首个控件即可,后续的控件不需要设置)
app:layout_constraintHorizontal_chainStyle="约束值"
//垂直链约束(注意这个设置给链的首个控件即可,后续的控件不需要设置)
app:layout_constraintVertical_chainStyle="约束值"
约束值可为以下三者之一:
1、spread
2、packed
3、spread_inside
(1)链约束的三种约束值
spread:控件平均分配父容器宽度剩余空间:
<?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"
android:orientation="horizontal">
<!--
chain
注意1、首个控件添加layout_constraintHorizontal_chainStyle链约束即可
注意2、每个控件start、end都必须添加约束。否则达不到预期效果。这点十分重要
-->
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tv1"
android:layout_width="100dp"
android:layout_height="100dp"
android:background="#ff0000"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="@id/tv2"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
tools:ignore="HardcodedText"
app:layout_constraintHorizontal_chainStyle="spread"
/>
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tv2"
android:layout_width="100dp"
android:layout_height="100dp"
android:background="#000000"
app:layout_constraintStart_toEndOf="@id/tv1"
app:layout_constraintEnd_toStartOf="@id/tv3"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
tools:ignore="HardcodedText" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tv3"
android:layout_width="100dp"
android:layout_height="100dp"
android:background="@color/purple_700"
app:layout_constraintStart_toEndOf="@id/tv2"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
tools:ignore="HardcodedText" />
</androidx.constraintlayout.widget.ConstraintLayout>
有了上述栗子,我们只需修改下layout_constraintHorizontal_chainStyle的属性值即可得到另外两种效果。
spread_inside:首尾控件在两端,其余控件平均分配父容器宽度剩余空间。
packed:所有控件紧贴且居中
(2)链约束和权重
链约束还支持权重,可在xml中进行如下设置。
// 水平链 配置权重
app:layout_constraintHorizontal_weight="权重值"
// 垂直链 配置权重
app:layout_constraintVertical_weight="权重值"
<?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"
android:orientation="horizontal">
<!--
chain配置权重
app:layout_constraintHorizontal_weight="xxx"
-->
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tv1"
android:layout_width="0dp"
android:layout_height="100dp"
android:background="#ff0000"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="@id/tv2"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
tools:ignore="HardcodedText"
app:layout_constraintHorizontal_chainStyle="spread"
app:layout_constraintHorizontal_weight="1"
/>
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tv2"
android:layout_width="0dp"
android:layout_height="100dp"
android:background="#000000"
app:layout_constraintStart_toEndOf="@id/tv1"
app:layout_constraintEnd_toStartOf="@id/tv3"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHorizontal_weight="1"
tools:ignore="HardcodedText" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tv3"
android:layout_width="0dp"
android:layout_height="100dp"
android:background="@color/purple_700"
app:layout_constraintStart_toEndOf="@id/tv2"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHorizontal_weight="1"
tools:ignore="HardcodedText" />
</androidx.constraintlayout.widget.ConstraintLayout>
四、常见辅助类
1、Guideline
可作为参考线,实际不会出现在布局中,这个控件使用率很高,也可以用来做一些百分比分割之类的需求,有着很好的屏幕适配效果。
android:orientation="" 辅助线的对齐方式值可为horizontal或vertical。
app:layout_constraintGuide_percent="" 取值[0,1],表示指导线距离父级宽度或高度的百分比。
app:layout_constraintGuide_begin="" 指导线距离父控件起始位置的距离
app:layout_constraintGuide_end="" 指导线距离父级结束位置的距离
如有一个控件需要在垂直控件上在父控件的30%位置
<?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"
tools:context=".MainActivity"
android:gravity="center"
>
<!-- 定义一根水平"Guideline",这条线为水平的,位置为父控件垂直的30%处-->
<androidx.constraintlayout.widget.Guideline
android:id="@+id/Guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.3" />
<!-- 控件在"Guideline"下,这样无论ConstraintLayout变多大控件始终在
ConstraintLayout的30%处-->
<TextView
android:layout_width="120dp"
android:layout_height="80dp"
android:background="@color/purple_500"
android:gravity="center"
android:text="A"
android:textColor="@color/black"
android:textSize="25sp"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/Guideline" />
</androidx.constraintlayout.widget.ConstraintLayout>
2、Group
被Group控件可以很好的实现多控件的显示、隐藏而不用关心控件所属的布局。
app:constraint_referenced_ids="控件1id,控件2id,等等"
<?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"
tools:context=".MainActivity"
android:gravity="center"
>
<TextView
android:id="@+id/btn1"
android:layout_width="100dp"
android:layout_height="60dp"
android:layout_marginTop="56dp"
android:background="@color/purple_500"
android:gravity="center"
android:text="btn1"
android:textColor="@color/black"
android:textSize="25sp"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/btn3"
android:layout_width="100dp"
android:layout_height="60dp"
android:layout_marginTop="280dp"
android:background="@color/purple_500"
android:gravity="center"
android:text="btn3"
android:textColor="@color/black"
android:textSize="25sp"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/btn2"
android:layout_width="100dp"
android:layout_height="60dp"
android:layout_marginTop="164dp"
android:background="@color/purple_500"
android:gravity="center"
android:text="btn2"
android:textColor="@color/black"
android:textSize="25sp"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<!--gone 时 三个TextView也随之消失-->
<androidx.constraintlayout.widget.Group
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="visible"
app:constraint_referenced_ids="btn1,btn2,btn3" />
</androidx.constraintlayout.widget.ConstraintLayout>
The end
参考:
官方文档