Android-ConstraintLayout#前山翻译

ConstraintLayout-约束布局

ConstraintLayout是一个ViewGroup,允许你以一种弹性的方式控制控件的位置和大小。

注明:ConstraintLayout是一个支持库,最低支持到Android系统的API级别为9(姜饼)。当然,随着时间的推移,我们计划不断的丰富它的API和性能,这篇文档将会说明这些变化。

下面是目前你可以使用的各种约束类型:

  • 相对定位
  • 外边距
  • 中心定位
  • 圆形定位
  • 可见性行为
  • 尺寸约束
  • 链式
  • 辅助对象

注明:在约束类型中目前还没有圆形定位的依赖。

也可以点击ConstraintLayout.LayoutParams查看更多的布局属性。

开发指南

Relative positioning -相对定位

相对定位是约束布局中一个创建基本块的布局方式之一。这些属性允许你相对一个控件定位另一个控件,也可以用横轴和纵轴来约束一个控件:

  • 横轴:左边,右边,开始和结束边
  • 纵轴:上面,下面和文字基准线

通俗来说的概念是通过提供一个控件的一边来约束其它控件的一边。

例如,为了定位按钮B在按钮A的右边(fig.1):


Fig.1-relative-positioning.png

你需要这样做:

<Button android:id="@+id/buttonA" ... />
<Button android:id="@+id/buttonB" ...
     app:layout_constraintLeft_toRightOf="@+id/buttonA" />
         

这个属性告诉系统,我们想让按钮B的左边被约束到按钮A的右边。这样一个定位的约束意味着系统将按钮B的左边和按钮A的右边定在同一个位置。


Fig.2-relative-positioning-constraints.png

下面是一些约束的属性(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-外边距

Fig.3-relative-positioning-margin.png

如果外边距被设置,要是控件存在的话也会被应用到相应的约束当中,强制在目标和源控件中留出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-centering-positioning.png

当出现这种情况时,约束的行为看起来就像两股对立的力作用在这个控件上一样(Fig.4);这个控件将会处在父容器的中间,有点像垂直约束。

Bias(轴)

默认的情况下,遇到对立的约束时会使控件保持在中间位置,但是你可以通过bias(轴)属性把控件一边拉向另外一边:

  • layout_constraintHorizontal_bias
  • layout_constraintVertical_bias


    Fig.5-centering-positioning-bias.png

    例如,下面的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度)


    Fig.6-circle1.png

    Fig.6-circle2.png

Visibility behavior-可见性行为

ConstraintLayout对设置View.GONE的控件有特殊的处理方式。

设置GONE的控件通常来说将不会显示,并且也不属于布局的一部分(如果被设置为GONE它们的实际尺寸将不会被改变)。

但是在布局的计算当中,被设置GONE的控件仍然会被计算,这是一个很大区别。

  • 对于已经完成的布局,他们的尺寸被认为是设置为0(基本上他们会被处理为一个点)。
  • 如果他们已经约束于其它的控件,它们仍然有约束作用,但任何的外边距将会被设置等同于0。


    Fig.7-visibility-behavior.png

    当你临时的设置控件为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-dimension-match-constraints.png

    第一,第二个跟其它的布局相类似,最后一个将会按照约束设置的方式重新确定控件的大小(参照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,显示一条最小的链,包含两个控件)。


Fig.9-chains.png

链式头部

链式可以由链式的第一个元素控制整个链条的属性(头部链条):


Fig.10-chains-head.png

在水平链条中最左边的为头部链条,垂直链条中最顶部的为头链条。

链式中外边距

链接中如果指定外边距,它们将会有效执行。在默认链式样式spread时,外边距将会从可分配的空间中扣除出来。

链式样式

当设置链条中第一个元素属性layout_constraintHorizontal_chainStyle或者layout_constraintVertical_chainStyle时,根据设置的chainStyle整个链条的行为都会改变(默认chainStyle是chain_spread):

  • CHAIN_SPREAD --所有元素平分开来 (默认样式)
  • Weighted chain -- 在CHAIN_SPREAD样式中, 如果有一些控件设置为match_constraint,它们将会分割空余空间
  • CHAIN_SPREAD_INSIDE -- 类似的,但是头元素和尾元素将不会散开,保持在父容器开始和结尾的位置
  • CHAIN_PACKED -- 链条中的元素被打包在一起. 设置横轴或者纵轴会影响到被打开元素的定位


    Fig.11-chains-styles.png
均分式链式

链条默认的方式是在可利用的空间中均等散开所有的元素。如果一个或者多个元素属性设置match_constraint,那么他们将会使用多余的可用空间(均等的划分空间)。在元素属性使用match_constaint时layout_constraintHorizontal和layout_constraintVertical_weight将会控制剩余空间的划分。例如,一条链式上包含的两个元素属性都使用match_constraint,第一元素使用比例为2,第二个使用比例为1,那么空间的划分为第一个元素是第二个元素的两倍。

辅助对象

想要提前了解性能方面的详情,你可以使用特殊的辅助对象,在约束布局中帮助你实现你的布局。目前来看,指南线对象允许你创建横向和纵向的指导线,它被定位与约束布局容器中。控件可以根据这样的指导线来约束自己已达到定位的目的。

在约束布局1.1版本中,Barrier和Group将会被加进来。


资料

翻译原文:ConstraintLayout

指南线:Guideline

郭霖:Android新特性介绍,ConstraintLayout完全解析

QQ音乐技术团队:ConstraintLayout入门指南

谷歌开发者:解析ConstraintLayout的性能优势

推荐阅读更多精彩内容