ConstraintLayout的使用
这篇文章主要根据官方文档的结构,加上自己的理解来介绍它的用法。
ConstraintLayout
翻译过来是约束布局,可以对子view添加各种约束条件达到某种目的,非常灵活。
ConstraintLayout
是一个ViewGroup
的导出类,可以用灵活的方式来放置部件和确定部件大小。
引入依赖
开始使用ConstraintLayout
前,需要在工程引入ConstraintLayout
依赖库。
添加以下依赖到你的build.gradle
文件中:
dependencies {
implementation 'com.android.support.constraint:constraint-layout:1.1.0'
}
开发指南
主要通过以下几个方面来介绍ConstraintLayout
的使用和特性:
- 相对定位
- 边距
- 居中和偏移
- 圆形定位
- 可见度的行为
- 部件尺寸的约束
- 比例
- 链条
相对定位
相对定位跟RelativeLayout非常像,一个部件相对另外一个部件的位置。如把ButtonB放到ButtonA的右边,可以这样写:
<Button android:id="@+id/buttonA" ... />
<Button android:id="@+id/buttonB" ...
app:layout_constraintLeft_toRightOf="@+id/buttonA" />
有以下可用的约束属性:
- 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
这些属性都是可以引用另外一个部件的id,或者parent(指的是引用父容器,实际指的是ConstraintLayout)
外边距
如果设置了margins,它会运用于相应的约束(如果存在的话),强制将margins当做一个空间在目标的边和原始的边之间,有以下有效的属性:
- android:layout_marginStart
- android:layout_marginEnd
- android:layout_marginLeft
- android:layout_marginTop
- android:layout_marginRight
- android:layout_marginBottom
注意这些属性的值只能是正数或者0
当连接了GONE的部件时的边距
如果约束目标的部件为GONE时,可以设置以下属性来设置边距,只在目标GONE时有效.
- layout_goneMarginStart
- layout_goneMarginEnd
- layout_goneMarginLeft
- layout_goneMarginTop
- layout_goneMarginRight
- layout_goneMarginBottom
注意目标为GONE时同时设置了layout_goneMarginStart和layout_marginStart,只有layout_goneMarginStart会有效
居中和偏移
看个例子
<android.support.constraint.ConstraintLayout ...>
<Button android:id="@+id/button" ...
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent/>
</>
这个例子控件添加了左边跟父容器对齐,右边也跟父容器对齐的约束。看是不可能发生,除非子控件的宽跟父容器一致。
实际上如果这样这种对立面的约束(横向或者竖向)会导致部件刚好居中,可以想象成两个相反方向的力度拉伸,力是相等的,可以类比拔河,双方的力一样,刚好居中。
偏移
对立面的约束默认是居中,可以通过设置以下两个属性进行偏向一边
* layout_constraintHorizontal_bias
* layout_constraintVertical_bias
值为0到1,如果是0.5,部件刚好居中
使用偏移,可以放置部件到自己想要的位置
例如把一个按钮放到水平的30%的位置,默认是50%。
<android.support.constraint.ConstraintLayout ...>
<Button android:id="@+id/button" ...
app:layout_constraintHorizontal_bias="0.3"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent/>
</>
圆形定位(1.1新增)
你可以通过一个部件的中心约束另外一个部件的中心,通过角度,距离。这使得你定位部件在一个圆上。对应的属性有:
- layout_constraintCircle : 引用另外一个部件的id
- layout_constraintCircleRadius : 到另一个部件中心点的距离,实际就是半径
- layout_constraintCircleAngle : 角度 (0 to 360)
例如: ButtonB 位于 ButtonA中心点的45度,中心点距离为100dp
<Button android:id="@+id/buttonA" ... />
<Button android:id="@+id/buttonB" ...
app:layout_constraintCircle="@+id/buttonA"
app:layout_constraintCircleRadius="100dp"
app:layout_constraintCircleAngle="45" />
可见度的行为
ConstraintLayout
有特殊处理被标记为GONE的部件(layout_goneMargin).
GONE的部件,通常不显示和不是layout一部分(实际上他们的dimension不改变当标记为GONE时 )
但是根据layout的计算,GONE仍然是它的一部分,有重大的区别:
对于布局的传递,他们的dimension认为是0(基本上他们可以当做一个点来看待)
如果他们约束了其他部件,它的所有margins当做为0
这种行为允许构建你能暂时标记GONE的部件的布局,而不是破坏布局。当做一些简单的动画时特别有用
尺寸的约束
- android:minWidth 设置最小的宽度
- android:minHeight 设置最小的高度
- android:maxWidth 设置最大的宽度
- android:maxHeight 设置最大的高度
这些值用在ConstraintLayout
,当他们的dimensions设置成WRAP_CONTENT的时候
部件尺寸的约束
部件的尺寸是通过设置android:layout_width
和 android:layout_height
属性指定的,有3种方式:
* 使用一个明确的尺寸值(字面值如123dp或者值引用)
* 使用WRAP_CONTENT,请求部件计算自己的值
* 使用0dp,等价于MATCH_CONSTRAINT,类似于其他layout的match_parent,在约束条件下可以用的最大的值
70)
前两种跟其他的布局类似。最后一种会重新计算部件通过适配设置的约束。如果边距有设置,计算时也会考虑边距。
重要提醒:ConstraintLayout
不推荐包含MATCH_PARENT的部件。类似行为可以使用MATCH_CONSTRAINT 这种方式,把相应的左/右,上/下约束设置成“parent”即可。
WRAP_CONTENT: 强制约束(1.1新增)
如果一个尺寸设置了WRAP_CONTENT,在1.1版本之前,他们会当做字面量来处理,意味着约束将没有限制结果的尺寸。通常这已经足够(处理更快点),但是一些情况下,你可以想要使用WRAP_CONTENT,仍然保持强制的约束限制结果的大小,这种情况下添加以下相应的属性:
- app:layout_constrainedWidth=”true|false”
- app:layout_constrainedHeight=”true|false”
MATCH_CONSTRAINT 尺寸(1.1新增)
当一个尺寸设置为MATCH_CONSTRAINT,默认行为的结果大小为是用所有可用的空间,有以下几个额外修改的属性:
layout_constraintWidth_min
andlayout_constraintHeight_min
: 设置最小的大小layout_constraintWidth_max
andlayout_constraintHeight_max
: 设置最大的大小
layout_constraintWidth_percent
andlayout_constraintHeight_percent
: 设置大小根据百分比
值可以是dp的字面值或者wrap,如果是wrap表示跟WRAP_CONTENT一样
百分比大小
使用百分比,需要设置下列事物:
* 尺寸需要设置成MATCH_CONSTRAINT (0dp)
* 这两个属性要设置成percent app:layout_constraintWidth_default=”percent” or app:layout_constraintHeight_default=”percent” (1.1之后不需要)
* 设置layout_constraintWidth_percent 或者 layout_constraintHeight_percent属性的值为0到1
比例
你可以声明一个部件尺寸的宽高比例,为了做到那样,你需要最少设置一个约束尺寸为0dp(也就是MATCH_CONSTRAINT),然后设置layout_constraintDimensionRatio 的比例值。例如:
<Button android:layout_width="wrap_content"
android:layout_height="0dp"
app:layout_constraintDimensionRatio="1:1" />
这个例子将设置高和宽一样
比例可以这样表达:
* 一个浮点数,代表宽高之间的比例
* 比例的格式”width:height”
也可以同时把宽度尺寸设置为MATCH_CONSTRAINT (0dp),这样情况系统设置最大的尺寸来满足所有的约束和保持这个比例。可以约束一一条指定的边基于另外一条边的大小。你可以在前面加上W,或者H。来分别约束宽或者高,例如:
<Button android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintDimensionRatio="H,16:9"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
设置基于高度大小满足(16:9)的宽.
链条
链条提供一组行为在一条单轴上(横向或者竖向),其他轴可以有独立的约束。
创建一个链条
如果通过双向连接将一组小部件连接到一起,就会被认为是一个链条。
链头
链条由链的第一个元素上的属性控制,链头是水平链的最左边的部件,也是垂直链的最顶层的部件。
边距
如果在连接上指定了页边距,就会考虑到它们。在扩展链的情况下,将从分配的空间中扣除
链条样式
当在链的第一个元素上设置属性layout_constraintHorizontal_chainStyle 或者 layout_constraintVertical_chainStyle时,链条的行为将根据指定的样式进行更改(默认是CHAIN_SPREAD)。
- CHAIN_SPREAD – 这些元素将会分散开来,相同间距 (default style)
Weighted chain – 在 CHAIN_SPREAD 模式下, 如果一些部件设置成 MATCH_CONSTRAINT, 他们将分配剩余空间(类似layout_weight)
CHAIN_SPREAD_INSIDE – 类似,但是链的端点不会分散开来
CHAIN_PACKED – 链条的组成部分将被打包在一起。然后,孩子的水平或垂直偏差属性会影响填充元素的位置
Weighted chains
链的默认行为是在可用空间中均匀地分布元素。如果一个或多个元素使用MATCH_CONSTRAINT,它们将使用可用的空闲空间(在它们之间平均分配)。属性layout_constraintHorizontal_weight 和 layout_constraintVertical_weight束的属性将控制如何使用匹配约束来在元素之间分配空间。例如,在一个包含两个元素的链上,使用匹配约束,第一个元素使用2的权重,第二个元素的权重为1,第一个元素占用的空间将是第二个元素的两倍
边距和链条 (在1.1)
当在链条上使用margins时,margins是附加的。
例如,在水平链上,如果一个元素定义了10dp的右边距,而下一个元素定义了5dp的左边距,那么这两个元素之间的边距是15 dp。
当计算链用来定位物品的剩余空间时,一个物品加上它的边缘被考虑在一起。剩余的空间不包含边距。
虚拟辅助对象
除了前面详细介绍的内在功能之外,你还可以在约束布局中使用特殊的助手对象来帮助您进行布局。目前,Guideline 允许您创建相对于约束布局容器的水平和垂直的指导方针。然后,可以通过将小部件限制在这些指导方针中来定位。在1.1中,也加入了Barrier(障碍)和Group(组)。
Guideline
工具类表示约束布局的指导助手对象。辅助对象不会显示在设备上。他们仅仅使用在约束布局内部。
Guideline分为 横向和竖向:
* 竖向是宽为0,高是父的约束布局的高
* 横向是高为0,宽是父的约束布局的宽
用3种方式定位一个Guideline
* 在布局中指定左或者顶部的距离(layout_constraintGuide_begin)
* 在布局中指定右边左或者底部的距离 (layout_constraintGuide_end)
* 在布局中指定一个宽高的百分比 (layout_constraintGuide_percent)
部件可以被Guideline约束,允许多个部件可以很容易地从一个Guideline中定位,或者允许使用百分比定位来进行响应式布局行为。
Barrier(界线)
一个Barrier可以引入多个部件作为输入,然后建立一条虚拟引导线,这条线基于基于最大部件在一条指定的边上。例如一条左边界线对齐所有的views
<android.support.constraint.Barrier
android:id="@+id/barrier"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:barrierDirection="start"
app:constraint_referenced_ids="button1,button2" />
Group(组)
这个类控制一组引用部件的可见度。部件引用添加通过逗号分开。例如:
<android.support.constraint.Group
android:id="@+id/group"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="visible"
app:constraint_referenced_ids="button4,button9" />
该组的可见性将应用于所引用的部件。这是一种方便的方法,可以轻松地隐藏/显示一组小部件,而无需以编程方式维护该集合。
Multiple groups
多个群组可以引用相同的小部件——在这种情况下,XML声明顺序将定义最终可见性状态(最后声明的组将拥有最后一个单词)
优化器(1.1版)
在1.1的版暴露了约束优化器,你可以通过添加标签app:layout_optimizationLevel指定哪些优化,用来应用到ConstraintLayout
元素中:
- standard: 只对direct和barrier约束进行优化
- direct: 优化直接的约束
- barrier:优化barrier的约束
- chain:优化链条的约束 (实验性的)
- dimensions:优化尺寸的测量(实验性的),减少匹配约束元素的测量的次数。
这个属性是一个掩码,所以您可以决定打开或关闭特定的优化,列出你想要的,例如
app:layout_optimizationLevel="direct|barrier|chain"