一. 简介
首先,和其他的布局一样,ConstraintLayout
和其它的 布局 一样是继承于 ViewGroup
。它的出现主要是为了解决布局嵌套过多的问题,以灵活的方式定位和调整 View
。学过 iOS开发
的小伙伴肯定都知道在xib
或者storyboard
里面的拖拽布局或者说约束布局,和我们这里的很像,但其实还是有很大的区别的。
ConstraintLayout
和其他的布局一样有以下这些的属性:
① View在左上右下四个方向和其他View之间的距离,值是 dp
1 2 3 4
| android:layout_marginStart (android:layout_marginLeft) android:layout_marginTop android:layout_marginEnd (android:layout_marginRight) android:layout_marginBottom
|
② View内部元素到View左上右下边框之间的距离,值是 dp
1 2 3 4
| android:paddingStart (android:paddingLeft) android:paddingTop android:paddingEnd (android:paddingRight) android:paddingBottom
|
③ 容器 内部的对齐方式 以及 容器相对于父容器的对齐方式
1 2
| android:gravity android:layout_gravity
|
二. ConstraintLayout
1.系统默认的布局样式
在Android Studio2.3
之后,创建一个layout文件,默认使用布局如下:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| <?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">
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hello World!" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
|
从上面可以发现 四个属性 用来表示 View 之间的关系(此处parent可以换成其他想要与之关联的View的控件 id):
1 2 3 4 5 6 7 8 9 10 11
| layout_constraintLeft_toLeftOf="parent"
layout_constraintTop_toTopOf="parent"
layout_constraintRight_toRightOf="parent"
layout_constraintBottom_toBottomOf="parent"
|
从上面可以发现 四个属性 用来表示 View 之间的关系(此处parent可以换成其他想要与之关联的View的控件 id):
1 2 3 4 5 6 7 8 9 10 11
| layout_constraintLeft_toRightOf="parent"
layout_constraintTop_toBottomOf="parent"
layout_constraintRight_toLeftOf="parent"
layout_constraintBottom_toTopOf="parent"
|
模板中声明了一个TextView
,且处于屏幕中间。如何做到的呢?
TextView
后面设置四个属性顾名思义都指定了TextView
与Parent
(父布局)的关系,约束布局如果不指定水平和竖直方向的百分比,默认是50%,所以会居中。
2. 设置 bisa
上面说到了系统默认约束布局的百分比是50%,那么百分比是怎么设置的呢?百分比设置后,系统是怎么计算的呢?
1 2 3 4 5
| layout_constraintHorizontal_bias="0.5"
layout_constraintVertical_bias="0.5"
|

我们来用小例子证实一下上面的说法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| <?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="400dp" android:layout_height="400dp" android:background="#cc6699" tools:context=".MainActivity">
<View android:layout_width="120dp" android:layout_height="120dp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintTop_toTopOf="parent"
android:background="#ff0000" />
<TextView android:layout_width="100dp" android:layout_height="100dp" android:text="Hello World!" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent"
android:background="#334455"
app:layout_constraintHorizontal_bias="0.4" app:layout_constraintVertical_bias="0.5" />
</androidx.constraintlayout.widget.ConstraintLayout>
|

根据我们的计算:0.4 = L / ( L + R ) = L / (400 - 100),可以得到 L = 120dp。这个值和我们用来放在TextView
左边测试的View的宽度一致,证明了我们的说法。
3. 设置 precent
当 ConstraintLayout
子布局的宽或高设置为0dp时,可以对宽或高设置百分比,百分比的取值范围是 0.0~1.0
,相对的是父容器的宽高大小。
1 2 3 4 5
| layout_constraintWidth_percent=""
设置竖方向占比来确定高度 layout_constraintHeight_percent=""
|
简单小例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| <?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="400dp" android:layout_height="400dp" android:background="#cc6699" tools:context=".MainActivity">
<TextView android:layout_width="0dp" android:layout_height="0dp" android:text="Hello World!" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent"
android:background="#334455"
app:layout_constraintWidth_percent="0.1" app:layout_constraintHeight_percent="0.9" />
</androidx.constraintlayout.widget.ConstraintLayout>
|

你会发现这个百分比只能改变宽高,不会改变相对位置,所以可以配和 bisa 使用。
4. 设置 ratio
当 layout_width
或者 layout_height
设置为0dp时,还可以通过 layout_constraintDimensionRatio
设置宽高比例。该比例默认表示 width:height
的值。
使用 layout_constraintDimensionRatio
设置宽度和高度的比值来灵活设置View的尺寸。如果想要表示高度:宽度则可以配置属性类似 h,1:9
的含义是 h:w=9:1
也可设置 w,9:1
是一样的。
简单小例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| <?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="400dp" android:layout_height="400dp" android:background="#cc6699" tools:context=".MainActivity">
<TextView android:layout_width="0dp" android:layout_height="0dp" android:text="Hello World!" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent"
android:background="#334455"
app:layout_constraintWidth_percent="0.1" app:layout_constraintDimensionRatio="h,1:9" />
</androidx.constraintlayout.widget.ConstraintLayout>
|

5. 设置 强制约束
首选请看下面的效果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| <?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="400dp" android:layout_height="400dp" android:background="#cc6699" tools:context=".MainActivity">
<Button android:id="@+id/btn1" android:layout_width="wrap_content" android:layout_height="wrap_content" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toBottomOf="parent" android:text="站位" />
<Button android:id="@+id/btn2" android:layout_width="wrap_content" android:layout_height="wrap_content" app:layout_constraintLeft_toRightOf="@id/btn1" app:layout_constraintTop_toTopOf="@id/btn1" app:layout_constraintRight_toRightOf="parent" android:layout_marginTop="40dp" android:text="测试测试测试测试测试测试测试测试测试测试测试测试" />
</androidx.constraintlayout.widget.ConstraintLayout>
|

怎么回事,不是应该右边不会超出父布局的么,我已经设置了layout_constraintRight_toRightOf="parent"
,这个就是设置了适应内容属性后出现的问题,此时需要强制使用约束宽度的属性(app:layout_constrainedWidth="true"
) ,你会发现效果正常了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| <?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="400dp" android:layout_height="400dp" android:background="#cc6699" tools:context=".MainActivity">
<Button android:id="@+id/btn1" android:layout_width="wrap_content" android:layout_height="wrap_content" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toBottomOf="parent" android:text="站位" />
<Button android:id="@+id/btn2" android:layout_width="wrap_content" android:layout_height="wrap_content" app:layout_constraintLeft_toRightOf="@id/btn1" app:layout_constraintTop_toTopOf="@id/btn1" app:layout_constraintRight_toRightOf="parent" android:layout_marginTop="40dp" android:text="测试测试测试测试测试测试测试测试测试测试测试测试" app:layout_constrainedWidth="true" />
</androidx.constraintlayout.widget.ConstraintLayout>
|

6. 设置 控件链条
通过 layout_constraintHorizontal_chainStyle
或 layout_constraintVertical_chainStyle
设置链式控件的样式。这个属性有点像 LinearLayout
中的 weight
属性平分布局。使用此属性,通常是权重分配不满足需求,但是又需要居中或者分配View
的空间
属性效果官方示例图:

使用此属性之前,需要把你即将连成链条的View
彼此之间建立关联关系,水平方向则是控件彼此左右关联,竖直方向则是上下关联,每相邻两个View之间必须紧紧关联id
。即是:将一个方向上的控件形成锁链(相互依赖),默认属性是 spread
。
① Spread Chain
View之间平分距离,包括左右两边也要平分。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| <?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="400dp" android:layout_height="400dp" android:background="#cc6699" tools:context=".MainActivity">
<Button app:layout_constraintHorizontal_chainStyle="spread"
android:id="@+id/btn1" android:layout_width="100dp" android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toLeftOf="@id/btn2"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toBottomOf="parent" android:text="左边" />
<Button android:id="@+id/btn2" android:layout_width="100dp" android:layout_height="wrap_content"
app:layout_constraintLeft_toRightOf="@id/btn1" app:layout_constraintRight_toLeftOf="@id/btn3"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toBottomOf="parent" android:text="中间" />
<Button android:id="@+id/btn3" android:layout_width="100dp" android:layout_height="wrap_content"
app:layout_constraintLeft_toRightOf="@id/btn2" app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toBottomOf="parent" android:text="右边" />
</androidx.constraintlayout.widget.ConstraintLayout>
|

② Spread Inside Chain
View之间平分距离,左右两边不要平分。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| <?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="400dp" android:layout_height="400dp" android:background="#cc6699" tools:context=".MainActivity">
<Button app:layout_constraintHorizontal_chainStyle="spread_inside"
android:id="@+id/btn1" android:layout_width="100dp" android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toLeftOf="@id/btn2"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toBottomOf="parent" android:text="左边" />
<Button android:id="@+id/btn2" android:layout_width="100dp" android:layout_height="wrap_content"
app:layout_constraintLeft_toRightOf="@id/btn1" app:layout_constraintRight_toLeftOf="@id/btn3"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toBottomOf="parent" android:text="中间" />
<Button android:id="@+id/btn3" android:layout_width="100dp" android:layout_height="wrap_content"
app:layout_constraintLeft_toRightOf="@id/btn2" app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toBottomOf="parent" android:text="右边" />
</androidx.constraintlayout.widget.ConstraintLayout>
|

③ Packed Chain
View之间彼此靠近,且整体居中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| <?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="400dp" android:layout_height="400dp" android:background="#cc6699" tools:context=".MainActivity">
<Button app:layout_constraintHorizontal_chainStyle="packed"
android:id="@+id/btn1" android:layout_width="100dp" android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toLeftOf="@id/btn2"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toBottomOf="parent" android:text="左边" />
<Button android:id="@+id/btn2" android:layout_width="100dp" android:layout_height="wrap_content"
app:layout_constraintLeft_toRightOf="@id/btn1" app:layout_constraintRight_toLeftOf="@id/btn3"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toBottomOf="parent" android:text="中间" />
<Button android:id="@+id/btn3" android:layout_width="100dp" android:layout_height="wrap_content"
app:layout_constraintLeft_toRightOf="@id/btn2" app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toBottomOf="parent" android:text="右边" />
</androidx.constraintlayout.widget.ConstraintLayout>
|

④ Packed Chain with Bisa
View之间彼此靠近,且整体位于设置的比例处。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| <?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="400dp" android:layout_height="400dp" android:background="#cc6699" tools:context=".MainActivity">
<Button app:layout_constraintHorizontal_chainStyle="packed" app:layout_constraintHorizontal_bias="0.9"
android:id="@+id/btn1" android:layout_width="100dp" android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toLeftOf="@id/btn2"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toBottomOf="parent" android:text="左边" />
<Button android:id="@+id/btn2" android:layout_width="100dp" android:layout_height="wrap_content"
app:layout_constraintLeft_toRightOf="@id/btn1" app:layout_constraintRight_toLeftOf="@id/btn3"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toBottomOf="parent" android:text="中间" />
<Button android:id="@+id/btn3" android:layout_width="100dp" android:layout_height="wrap_content"
app:layout_constraintLeft_toRightOf="@id/btn2" app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toBottomOf="parent" android:text="右边" />
</androidx.constraintlayout.widget.ConstraintLayout>
|

参考文章
布局大杀器—ConstraintLayout