ConstrainLayout【译】

/ Android布局 / 没有评论 / 545浏览

原文地址

https://developer.android.google.cn/reference/android/support/constraint/ConstraintLayout

介绍

ConstrainLayout是一个允许开发者灵活地设置控件的位置和大小的ViewGroup。 只要你使用的Android系统版本在9以上,你便可以通过添加依赖的方式来使用ConstrainLayout.

使用

添加依赖

implementation 'com.android.support.constraint:constraint-layout:1.1.3'

常用约束

相对定位(Relative positioning)

相对定位是ConstrainLayout构建布局的一种基本方式。相对定位约束可以帮助我们通过一个给定的Widget来摆放另外一个Widget。我们可以在横纵两个方向上约束Widget。

横向: left, right, start and end sides 纵向: top, bottom sides and text baseline

一般思路是将一个 Widget的给定侧约束到其他Widget的另一侧。

比如,把button B放置到button A的右侧(下图)

alt

实现可以如下

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

上述代码就是告诉系统,我们想让button B的左侧约束到button A的右侧。这样一个位置约束意味着,系统将让button A的右侧和button B的左侧在X轴上具有相同的位置。

此类相对位置属性还有很多,具体如下: alt

这些属性通过引用id来代表一个Widget,或者使用parent来代表父布局

<Button android:id="@+id/buttonB" ...
  app:layout_constraintLeft_toLeftOf="parent" />
         

边距(Margins)

alt

如果设置了边距,则它们将应用于相应的约束,将边距强制设置为目标Widget和源Widget之间的空间。通常的布局边距属性就可以达到此效果。

注意: 边距只能是正数或等于零,采用Dimension形式。

约束目标GONE后边距处理 (Margins when connected to a GONE widget)

当约束目标的可见性为View.GONE时,你还可以使用以下属性指示要使用的不同边距值:

居中定位和位置偏差

ConstraintLayout的一个有用方面是它如何处理“不可能”的约束。例如,如果我们有如下代码:

<android.support.constraint.ConstraintLayout ...>
    <Button android:id="@+id/button" ...
         app:layout_constraintLeft_toLeftOf="parent"
         app:layout_constraintRight_toRightOf="parent"/>
         </>

除非ConstraintLayout恰好具有与Button完全相同的大小,否则两个约束不能同时满足(双方都不能成为我们想要它们的位置)。

alt

在这种情况下,约束的作用就像是相反的力量将Widget拉平(上图);这样Widget最终将会在父容器中居中显示。这种使用方式在纵轴方向上同样适用。

偏差(Bias)

遇到这种相反的约束时的默认设置是使Widget居中;但是你可以使用偏差属性调整定位以使一侧偏向另一侧。

例如,如下代码将使左侧具有30%的偏差而不是默认的50%,使得左侧将更短,Widget更倾向于左侧(具体效果如下图):

<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/>
         </>

alt

使用偏差属性,你可以制作更好地适应屏幕尺寸变化的用户界面。

环形定位(Circular positioning (Added in 1.1))

你可以以距离或者角度来约束一个Widget中心相对于另一个Widget的中心。这样我们就可以将Widget放置到一个圆环上。具体属性如下:

alt alt

<Button android:id="@+id/buttonA" ... />
  <Button android:id="@+id/buttonB" ...
      app:layout_constraintCircle="@+id/buttonA"
      app:layout_constraintCircleRadius="100dp"
      app:layout_constraintCircleAngle="45" />

可见性行为(Visibility behavior)

ConstraintLayout对于可见性为View.GONE的Widget有明确的处理方式。

GONE widget,一般情况下,将不会显示在界面上,同时也不再是布局中的一部分。

但就布局计算而言,GONE Widget仍然是其中的一部分,这是有很大区别的。

alt

这种特定的行为可以满足你在不破坏布局的情况下构建布局,只需要暂时将对应的Widget标记为GONE即可,这在构建简单的布局动画时是很有用的。

如上图,当A GONE后,B使用的左边距是B相对于A的边距。在某些情况下,这个边距可能并不是你所需要的(比如,A相对于容器存在20dp的左边距,B相对于A有40dp的左边距,当A被标记为GONE后,B相对于容器就会存在40dp的左边距)。因此,你可以指定在连接到的Widget标记为GONE时的margin作为备用边距值。具体看上一章节的【约束目标GONE后边距处理】。

尺寸约束(Dimensions constraints)

ConstraintLayout最小尺寸和最大尺寸

通过如下属性你可以给ConstrainLayout定义最大或是最小尺寸。

当其尺寸设置为WRAP_CONTENT时,这些最小和最大尺寸将会被ConstraintLayout使用到。

Widgets尺寸约束

Widgets的尺寸需要通过如下三种方式设置android:layout_widthandroid:layout_height来明确。

alt

前两种设置的效果和其他布局一样。最后一个将以匹配所设置的约束的方式调整Widget的大小(上图中(a)wrap_content,(b)0dp)。如果设置来边距,它们也将被计算在内(上图中(c)0dp with margin)。

重要 针对ConstrainLayout中的Widget,我们不推荐使用MATCH_PARENT。我们可以通过使用MATCH_CONSTRAINT配合约束 Widget 的left/right或者top/bottom 到**“parent”**来定义类似的行为。

WRAP_CONTENT:强制执行约束 (Added in 1.1)

如果一个尺寸设置为WRAP_CONTENT,在1.1版本之前,他们将会被定义为数值类的尺寸大小,约束将不会限制结果尺寸。一般情况下这样已经足够满足需求并且运行速度也是很快的,但是在某些情况下,你可能想用WRAP_CONTENT来设置尺寸,同时也想强制约束来限制结果布局尺寸。这种情况下,你可以使用如下属性:

MATCH_CONSTRAINT(Added in 1.1)

当Widget的尺寸被设置为MATCH_CONSTRAINT时,默认的结果就是使用所有可用的空间。如下几个额外的属性可以被使用到:

最小值和最大值(Min and Max)

为min和max指示的值可以是Dp单位,也可以是“wrap”,它将使用与WRAP_CONTENT将执行的值相同的值

百分比尺寸(Percent dimension)

要使用百分比,你需要做如下配置:

比率

你可以定义Widget的宽高比例。为了实现这个效果,宽高中至少又一个设置为0dp(i.e.,MATCH_CONSTRAINT), 然后给** layout_constraintDimensionRatio**指定一个比例值,如下

 <Button android:layout_width="wrap_content"
     android:layout_height="0dp"
     app:layout_constraintDimensionRatio="1:1" />

这段代码将设置button的宽高一样。比例值可以通过如下两种方式设置:

在宽高都设置为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的比例来设置button的高度,而宽度将匹配父布局的约束。也就是这种情况下宽度:高度=16:9,由宽度来决定高度。

链(chain)

链在单个轴(水平或垂直)上提供组群行为。另一个轴可以独立约束

创建一个链

如果一组Widgets通过双向连接链接在一起,则它们被视为链。(下图展示的是一个由两个Widget组成的最小的链)

alt

链头

链由在链的第一个元素上设置的属性控制(我们可以将其视为链的“头”)

alt

头部是水平链的最左侧Widget,垂直链的最顶部Widget。

链间边距

如果在双向连接上指定了边距,则他们将会被计算在内。在扩散链的情况下,将从分配的空间中减去这些边距

链Style

在链的第一个元素上设置属性layout_constraintHorizo​​ntal_chainStylelayout_constraintVertical_chainStyle时,链的行为将根据指定的样式更改(默认为CHAIN_SPREAD

alt

权重链

链的默认行为是在可用空间中平均分布元素。如果一个或多个元素使用MATCH_CONSTRAINT,则它们将使用可用的空白空间(他们之间平等分配)。 layout_constraintHorizo​​ntal_weightlayout_constraintVertical_weight属性将控制如何使用MATCH_CONSTRAINT在元素之间分配空间。例如,在使用MATCH_CONSTRAINT的包含两个元素的链上,第一个元素使用权重2,第二个元素使用权重1,第一个元素占用的空间将是第二个元素占用的空间的两倍。

边距和链(1.1版本)

在链中的元素上使用边距时,边距是相加的 例如,在水平链上,如果一个元素定义了10dp的右边距而下一个元素定义了5dp的左边距,则这两个元素之间产生的边距为15dp。 在计算链用于定位项目的剩余空间时,会同时考虑项目及其边距。剩余空间不包含边距。

虚拟助手(Virtual Helper objects)

除了之前详述的内在功能外,您还可以使用ConstraintLayout中的特殊帮助程序对象来帮助您进行布局。现在,Guideline可以帮助你创建相对于ConstraintLayout容器定位的水平和垂直Guideline。然后Widgets可以被约束到这些Guideline上。在1.1版本中,Barrier和Group也别加入进来。

优化器(in 1.1)

在1.1版本中,我们提供约束优化器。你可以通过将标记app:layout_optimizationLevel添加到ConstraintLayout元素来决定应用哪些优化。

此属性是一个掩码,因此您可以通过列出所需的优化来决定打开或关闭特定的优化。例如

app:layout_optimizationLevel="direct|barrier|chain"