ConstraintLayout-约束布局
ConstraintLayout是一个ViewGroup,允许你以一种弹性的方式控制控件的位置和大小。
注明:ConstraintLayout是一个支持库,最低支持到Android系统的API级别为9(姜饼)。当然,随着时间的推移,我们计划不断的丰富它的API和性能,这篇文档将会说明这些变化。
下面是目前你可以使用的各种约束类型:
- 相对定位
- 外边距
- 中心定位
- 圆形定位
- 可见性行为
- 尺寸约束
- 链式
- 辅助对象
注明:在约束类型中目前还没有圆形定位的依赖。
也可以点击ConstraintLayout.LayoutParams查看更多的布局属性。
开发指南
Relative positioning -相对定位
相对定位是约束布局中一个创建基本块的布局方式之一。这些属性允许你相对一个控件定位另一个控件,也可以用横轴和纵轴来约束一个控件:
- 横轴:左边,右边,开始和结束边
- 纵轴:上面,下面和文字基准线
通俗来说的概念是通过提供一个控件的一边来约束其它控件的一边。
例如,为了定位按钮B在按钮A的右边(fig.1):
你需要这样做:
<Button android:id="@+id/buttonA" ... />
<Button android:id="@+id/buttonB" ...
app:layout_constraintLeft_toRightOf="@+id/buttonA" />
这个属性告诉系统,我们想让按钮B的左边被约束到按钮A的右边。这样一个定位的约束意味着系统将按钮B的左边和按钮A的右边定在同一个位置。
下面是一些约束的属性(Fig.2):
- 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):
<Button android:id="@+id/buttonB" ...
app:layout_constraintLeft_toLeftOf="parent" />
Margins-外边距
如果外边距被设置,要是控件存在的话也会被应用到相应的约束当中,强制在目标和源控件中留出margin的距离。通常布局的外边距属性对约束布局也有效:
- android:layout_marginStart
- android:layout_marginEnd
- android:layout_marginLeft
- android:layout_marginTop
- android:layout_marginRight
- android:layout_marginBottom
注明:一个外边距只能是正数,可以取0或者其它的尺寸。
当约束的是一个gone属性的控件的外边距
当一个定位约束控件的Visibilty设置为View.GONE时,你同样可以设置一个不同的外边距值,下面是可以使用的属性:
- layout_goneMarginStart
- layout_goneMarginEnd
- layout_goneMarginLeft
- layout_goneMarginTop
- layout_goneMarginRight
- layout_goneMarginBottom
中心定位和轴
ConstraintLayout非常有用的一面是可以处理一些不可能的约束。例如,下列的情况:
<android.support.constraint.ConstraintLayout ...>
<Button android:id="@+id/button" ...
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"/>
</android.support.constraint.ConstraintLayout>
除非ConstraintLayout恰好和Button的尺寸一样大小,否则同时约束两边的话会达不到想要的效果(在左右两边不能放在我们想放的位置)。
当出现这种情况时,约束的行为看起来就像两股对立的力作用在这个控件上一样(Fig.4);这个控件将会处在父容器的中间,有点像垂直约束。
Bias(轴)
默认的情况下,遇到对立的约束时会使控件保持在中间位置,但是你可以通过bias(轴)属性把控件一边拉向另外一边:
- layout_constraintHorizontal_bias
-
layout_constraintVertical_bias
例如,下面的Button将会被向左拉30%,而不是默认的50%。这样的话左边的距离会更短,控件会靠向左边(Fig.5):
<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/>
</android.support.constraint.ConstraintLayout>
使用轴属性,你可以精巧的制作用户界面,让它更好适应屏幕尺寸变化的显示出来。
Circular positioning(Added in 1.1)-圆形定位,将在1.1版本中加入
你可以以一定的角度,一定的长度约束一个控件的中心相对与另外一控件的中心。这个允许你以圆的方式定位一个控件(Fig.6),下面是一些可以使用的属性:
- layout_constraintCircle : 相对于其它控件的id
- layout_constraintCircleRadius : 相对于其它控件中心的距离
-
layout_constraintCircleAngle : 控件所处的角度(0-360度)
Visibility behavior-可见性行为
ConstraintLayout对设置View.GONE的控件有特殊的处理方式。
设置GONE的控件通常来说将不会显示,并且也不属于布局的一部分(如果被设置为GONE它们的实际尺寸将不会被改变)。
但是在布局的计算当中,被设置GONE的控件仍然会被计算,这是一个很大区别。
- 对于已经完成的布局,他们的尺寸被认为是设置为0(基本上他们会被处理为一个点)。
-
如果他们已经约束于其它的控件,它们仍然有约束作用,但任何的外边距将会被设置等同于0。
当你临时的设置控件为GONE时,这种特殊的行为允许做一些简单的动画来实现创建的布局,并且没有破坏布局。
注明:当连接A时B定义的外边距依然有效(参考Fig.7的例子)。在一些例子中,这可能不是你想要的外边距(例如:A相对于容器左外边距100dp,B相对于A左外边距只有16dp,设置A值GONE,B相对于容器左外边距为16dp)。针对这种情况,当连接的控件设置为GONE时,你可以指定一个二选一的外边距作为使用(参考上面的属性)。
Dimensions constraints-尺寸约束
在约束布局中的最小尺寸
你可以定义约束布局的最小和最大尺寸:
- android:minWidth 设置布局最小宽度
- android:minHeight 设置布局最小高度
- android:maxWidth 设置布局最大宽度
- android:maxHeight 设置布局最大高度
当它的尺寸被设置为wrap_cntent是,约束布局的最小最大尺寸才有使用效果。
控件尺寸约束
控件尺寸可以通过设置android:layout_width和android:layout_height属性指定大小,下面有三种方式:
- 使用指定尺寸(一个数字如123dp或者引用尺寸id)
- 使用wrap_content,表示控件默认自身的大小
-
使用0pd,等同于"match_constraint"
第一,第二个跟其它的布局相类似,最后一个将会按照约束设置的方式重新确定控件的大小(参照Fig.8,(a)是warp_content),(b)是0dp)。如果设置外边距,它们将会重新计算大小(Fig.8,(c)设置0dp )。
重要:在约束布局中不推荐控件使用match_parent值。当相对于"parent"约束左右上下时,类似的行为被定义使用match_constraint。
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 and layout_constraintHeight_min : 设置最小的尺寸
- layout_constraintWidth_max and layout_constraintHeight_max : 设置最大的尺寸
- layout_constraintWidth_percent and layout_constraintHeight_percent : 设置占父控件的比例
最小和最大
尺寸值可以用dp为单位指定最小或者最大的尺寸,或者使用等值"wrap_content"属性效果的“wrap"。
百分比尺寸
为了使用百分比,你需要设置如下:
- 这个尺寸应该被设置为match_constraint(0dp)
- 默认应该设置的百分比app:layout_constraintWidth_default="percent" 和 app:layout_constraintHeight_default="percent" (注明:在1.1测试版本中是必须的,但是在接下来的版本中如果百分比属性被定义则不再需要)
- 接着设置layout_constraintWidth_percent和layout_constraintHeight_percent的属性值在0到1之间
比例
你可以以比例的方式定义一个控件的尺寸。要这样做的话,你必须至少设置一个约束的尺寸为0dp(match_constraint),然后再设置属性layout_constraintDeminsRatio一个比例,例如:
<Button android:layout_width="wrap_content"
android:layout_height="0dp"
app:layout_constraintDimensionRatio="1:1" />
设置按钮的高度和宽度是一样的。
这个比例也可以这样表达:
- 一个浮点数的值,表示宽高的比例
- 一个比例等于“宽:高”
如果同时设置宽高为match_constraint(0dp),你也可以使用比例。在这种情况下,系统会自动设置最大的尺寸去满足所有的约束,并且会维持指定的比例。为了在一个尺寸的基础之上去约束一个指定的边,你可以先添加 w 或者 h,为了分别约束宽和高。例如一个尺寸被两个目标约束(宽度为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的比例。
Chains-链式
链式以相同轴(水平或竖直)的方式提供以组为单位的相似行为,其它的轴可以独立的被约束。
创建一条链式
如果许多控件以双向的方式连接,那么它们被认为是一条链(Fig.9,显示一条最小的链,包含两个控件)。
链式头部
链式可以由链式的第一个元素控制整个链条的属性(头部链条):
在水平链条中最左边的为头部链条,垂直链条中最顶部的为头链条。
链式中外边距
链接中如果指定外边距,它们将会有效执行。在默认链式样式spread时,外边距将会从可分配的空间中扣除出来。
链式样式
当设置链条中第一个元素属性layout_constraintHorizontal_chainStyle或者layout_constraintVertical_chainStyle时,根据设置的chainStyle整个链条的行为都会改变(默认chainStyle是chain_spread):
- CHAIN_SPREAD --所有元素平分开来 (默认样式)
- Weighted chain -- 在CHAIN_SPREAD样式中, 如果有一些控件设置为match_constraint,它们将会分割空余空间
- CHAIN_SPREAD_INSIDE -- 类似的,但是头元素和尾元素将不会散开,保持在父容器开始和结尾的位置
-
CHAIN_PACKED -- 链条中的元素被打包在一起. 设置横轴或者纵轴会影响到被打开元素的定位
均分式链式
链条默认的方式是在可利用的空间中均等散开所有的元素。如果一个或者多个元素属性设置match_constraint,那么他们将会使用多余的可用空间(均等的划分空间)。在元素属性使用match_constaint时layout_constraintHorizontal和layout_constraintVertical_weight将会控制剩余空间的划分。例如,一条链式上包含的两个元素属性都使用match_constraint,第一元素使用比例为2,第二个使用比例为1,那么空间的划分为第一个元素是第二个元素的两倍。
辅助对象
想要提前了解性能方面的详情,你可以使用特殊的辅助对象,在约束布局中帮助你实现你的布局。目前来看,指南线对象允许你创建横向和纵向的指导线,它被定位与约束布局容器中。控件可以根据这样的指导线来约束自己已达到定位的目的。
在约束布局1.1版本中,Barrier和Group将会被加进来。
资料
翻译原文:ConstraintLayout
指南线:Guideline
郭霖:Android新特性介绍,ConstraintLayout完全解析
QQ音乐技术团队:ConstraintLayout入门指南
谷歌开发者:解析ConstraintLayout的性能优势