Bootstrap

Android ConstraintLayout属性细化

这篇文章是基于Android ConstraintLayout完全解析和性能分析(章节一)基础上对属性的深入详解,如果之前对Android ConstraintLayout不了解或者不会使用的,请查看章节一的内容。若是有一定的了解,想深入对ConstraintLayout属性的了解及性能的分析,请直接阅读本章节内容。

一、ConstraintLayout属性讲解

先简单了解一下我们使用ConstraintLayout要用到的一些基本方位属性,如下表所示:

属性描述
app:layout_constraintLeft_toLeftOf把A的left side放在B的left side(左边对齐)
app:layout_constraintLeft_toRightOf把A的left side放在B的right side(左边相对右边对齐)
app:layout_constraintRight_toLeftOf把A的right side放在B的left side(右边相对左边对齐)
app:layout_constraintRight_toRightOf把A的right side放在B的right side(右边对齐)
app:layout_constraintTop_toTopOf把A的top side放在B的top side(顶部对齐)
app:layout_constraintTop_toBottomOf把A的top side放在B的bottom side(顶部相对底部对齐)
app:layout_constraintBottom_toTopOf把A的bottom side放在B的top side(底部相对顶部对齐)
app:layout_constraintBottom_toBottomOf把A的bottom side放在B的bottom side(底部对齐)
app:layout_constraintStart_toEndOf把A的start position放在B的end position(起始位置相对结束位置对齐)
app:layout_constraintStart_toStartOf把A的start position放在B的start position(起始位置对齐)
app:layout_constraintEnd_toStartOf把A的end position放在B的start position(结束位置相对起始位置对齐)
app:layout_constraintEnd_toEndOf把A的end position放在B的end position(结束位置对齐)
app:layout_constraintBaseline_toBaselineOf把A的bottom side放在B的top side(基准线对齐)

注意:属性的命名空间是app

一看这么多属性,估计整个人都不健康了,那让我们先看一个简单的例子吧:

<android.support.constraint.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">

    <Button
        android:id="@+id/button4"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>

通过以上的这段布局,既可以完成下图所展示的布局。
在这里插入图片描述
让一个控件在屏幕居中是不是特别简单,那让我们在看一个不同方位的控件展示,代码如下:

<android.support.constraint.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">

    <Button
        android:id="@+id/button2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginLeft="8dp"
        android:layout_marginTop="8dp"
        android:text="Button"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/button3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="8dp"
        android:layout_marginEnd="8dp"
        android:layout_marginRight="8dp"
        android:text="Button"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/button4"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginLeft="8dp"
        android:layout_marginBottom="8dp"
        android:text="Button"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent" />

    <Button
        android:id="@+id/button5"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginEnd="8dp"
        android:layout_marginRight="8dp"
        android:layout_marginBottom="8dp"
        android:text="Button"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent" />
</android.support.constraint.ConstraintLayout>

展示效果如下图:
在这里插入图片描述
有没有感脚这些属性特别像RelativeLayout中的android:layout_alignParentXXX,没错,是特别像,但是作用会有略微不同。

上面讲述了让控件相对于屏幕位置展示的效果,那如果想根据控件和控件之间的相对位置进行摆放的话,那么可以参考如下的使用方式进行处理:

<android.support.constraint.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">

    <Button
        android:id="@+id/button2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="A"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.317"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.444" />

    <Button
        android:id="@+id/button7"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginEnd="52dp"
        android:layout_marginRight="52dp"
        android:text="B"
        app:layout_constraintBottom_toBottomOf="@+id/button2"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="@+id/button2"
        app:layout_constraintVertical_bias="0.0" />

</android.support.constraint.ConstraintLayout>

布局的代码页很简单,就是把A控件作为参照位置,然后再根据A的位置来定位B控件的相对位置。
在这里插入图片描述

那么通过上面的例子,你会发现,RelativeLayout的相对位置的操作,ConstraintLayout也能轻易实现。需要说明的是:这些属性的值既可以是parent,也可以是某个View的id

二、偏斜(Bias)

在使用LinearLayout的时候,我们通常会使用Gravity来将水平或者垂直排列的控件按照权重的分配进行排列。而在ConstraintLayout中,它提供了bias属性来对控件进行权重的分配。

<android.support.constraint.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">

       <Button
        android:id="@+id/button2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="8dp"
        android:layout_marginBottom="8dp"
        android:text="A"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintHorizontal_bias="0.25"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</android.support.constraint.ConstraintLayout>

以上代码我们可以简单的看出,当一个控件被约束在屏幕的左侧,又被约束在屏幕的右侧,结果这个控件显示在了中间的位置,为什么? (1) 当使用了bias属性并设置了0.25的偏移量之后,我们发现控件在水平方向上向左偏移了屏幕宽度的1/4距离 (2) 如果我们把偏移值改成0.75,我们可以看到控件在水平方向上向右偏移了1/4的距离。

效果图如下:
在这里插入图片描述

那么有的同学可能就会有疑问了,既然横向可以设置屏幕的占比,那纵向是不是也有相应的属性呢,恭喜你答对了,是有的。

属性描述
app:layout_constraintHorizontal_bias水平方向偏移系数
app:layout_constraintVertical_bias垂直方向偏移系数

需要注意的是,它的取值区间为:0~1

三、GONE不是真的GONE

我们在使用RelativeLayout开发时,经常会碰到这么一种逻辑,当某个数据为空的时候,该数据所绑定的控件则GONE掉。那么这样会出现这样的问题,例如有三个控件A、B、C垂直排列,B在A的下方,C在B的下方,那B隐藏(GONE)掉了之后,由于C对于A并没有依赖关系,所以会导致页面错误。这个问题ConstraintLayout给出了很好的解决方案。当在ConstraintLayout中,若一个控件隐藏(GONE)之后,它会变成一个点,因此对于把该控件作为参考控件的其它控件依然具有约束作用。

当这个控件隐藏之后,我们还可以参照这个隐藏的控件对其他控件设置边距的属性。

属性描述
app:layout_goneMarginLeft隐藏控件左边距
app:layout_goneMarginRight隐藏控件右边距
app:layout_goneMarginTop隐藏控件顶部边距
app:layout_goneMarginBottom隐藏控件底部边距
app:layout_goneMarginStart隐藏控件起始边距
app:layout_goneMarginEnd隐藏控件结束边距

四、宽高比

1、View的宽高比

在ConstraintLayout中,还可以将宽定义成高的一个比例或者高定义成宽的比例。首先,需要先将宽或者高设置为0dp(即MATCH_CONSTRAINT),既要适应约束条件。然后通过layout_constraintDimensionRatio属性设置一个比例即可。这个比例可以是“浮点数”,表示宽度和高度之间的比例;也可以是“宽度:高度”形式的比例。比如:

<android.support.constraint.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:layout_width="wrap_content"
        android:layout_height="0dp"
        android:text="-------------------宽高比2:1-------------------"
        app:layout_constraintDimensionRatio="2:1"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"/>
</android.support.constraint.ConstraintLayout>

这里将按钮的高度设置为宽度的一半了。如下图所示:
在这里插入图片描述
如果宽和高都设置为0dp(即MATCH_CONSTRAINT),那么layout_constraintDimensionRatio的值需要先加一个"W,宽度:高度"或者"H,宽度:高度"来表示约束宽度或者高度,代码如下:

<android.support.constraint.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:text="Button1"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintDimensionRatio="h,10:6"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"/>

</android.support.constraint.ConstraintLayout>

效果图如下:
在这里插入图片描述
这例子是说,首先宽度将满足父布局的约束,然后将安装10:6的比例设置高度。

2、View百分比宽高

ConstraintLayout还能使用百分比来设置view的宽高,要使用百分比宽度或高度需要设置成0dp(即MATCH_CONSTRAINT)。
然后设置如下属性即可:

app:layout_constraintWidth_default="percent" //设置宽为百分比 
app:layout_constraintWidth_percent="0.3" //0到1之间的值
或
app:layout_constraintHeight_default="percent" //设置高为百分比 
app:layout_constraintHeight_percent="0.3" //0到1之间的值

其中layout_constraintHeight_default或者layout_constraintWidth_default的属性有三种类型:percent、spread、wrap,默认的为percent。

例子代码如下:

<android.support.constraint.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:text="Button1"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintWidth_percent="0.3"
        app:layout_constraintWidth_default="percent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"/>

</android.support.constraint.ConstraintLayout>

效果图如下:
在这里插入图片描述

五、复杂布局的福星-Chain属性

Chain链时一种特殊的约束让多个chain链链接的Views能够平分剩余空间位置,在Android传统布局特征里面最相似的应该是LinearLayout中的权重比weight,但Chains链能做到的远远不止权重比weight的功能。如果要实现一个控件之间的链结构,我们可以将这些控件之间建立起互相的约束关系,并在这些关系的基础上选择创建水平方向的链还是垂直方向的链。

官方提供了一共有5种样式的链:
在这里插入图片描述

我们可以通过下面的方式设置:

app:layout_constraintHorizontal_chainStyle="spread|spread_inside|packed"
或者
app:layout_constraintVertical_chainStyle="spread|spread_inside|packed"

在这里需要注意的是:在Chain的第一个组件上设置chainStyle,切记 切记

1、属性参数和值

对于Chian属性的种类来说,一共两种:水平方向(Horizontal)和垂直方向(Vertical)

属性描述
app:layout_constraintHorizontal_chainStyle水平方向上的Chain
app:layout_constraintVertical_chainStyle垂直方向上的Chain

对于Chain属性的模式来说,一共三种:展开(spread)、内部展开(spread_inside)、包裹(packed)

2. Spread链模式

spread模式会会把空间平均分配开来,每个View占有各自的平分空间,它是Chain属性的默认模式。

在该模式下,在设置View的宽度和高度为非0dp时,展示效果如下:
在这里插入图片描述
当使用了这个模式的时候,我们还可以配合weight属性设置spread的权重,在设置权重的时候,我们需要将控件的width或者height设置成0dp,并设置layout_constraintHorizontal_weight或者layout_constraintVertical_weight的值:

属性描述
app:layout_constraintVertical_weight垂直方向的控件权重
app:layout_constraintHorizontal_weight水平方向的控件权重

通过权重的设置,如图:
在这里插入图片描述

3. Spread Inside链模式

spread inside模式是在Spread的基础上,把两边最边缘的两个View到外向父组件边缘的距离去除,然后让剩余的Views在剩余的空间内部平分空间。

在该模式下,在设置View的宽度和高度为非0dp时,展示效果如下:
在这里插入图片描述

4、Packed链模式

packed模式很直观,它将所有Views聚拢在一起,控件和控件之间不留间隙,并将聚拢之后的Views居中显示。

在该模式下,在设置View的宽度和高度为非0dp时,展示效果如下:
在这里插入图片描述

当我们使用了Packed模式了之后,我们还可以通过bias参数对聚拢在一起的Views进行位置的调整。
在这里插入图片描述

5、XML中设置Chain示例

设置Chain属性需要保证两个条件:

  • 定义chain链的约束条件
  • 在Chain的第一个组件上设置chainStyle。
<android.support.constraint.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">

    <Button
        android:id="@+id/button16"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button"
        app:layout_constraintEnd_toStartOf="@+id/button17"
        app:layout_constraintVertical_chainStyle="packed"
        app:layout_constraintStart_toStartOf="parent"
        tools:layout_editor_absoluteY="39dp" />

    <Button
        android:id="@+id/button17"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button"
        app:layout_constraintEnd_toStartOf="@+id/button18"
        app:layout_constraintStart_toEndOf="@+id/button16"
        tools:layout_editor_absoluteY="39dp" />

    <Button
        android:id="@+id/button18"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@+id/button17"
        tools:layout_editor_absoluteY="39dp" />
</android.support.constraint.ConstraintLayout>

6、GuideLine的使用

GuideLine只是用在ConstraintLayout布局里面的一个工具类,用于辅助布局,类似于辅助线,可以设置android:orientation属性来确定是横向还是纵向。

重要的是Guideline是不会显示到界面上的,默认是GONE的。

方向描述
android:orientation方向

创建了GuideLine之后,我们可以设置参考线的初始位置:

权重属性描述
app:layout_constraintGuide_begin以View的起始位置为参照物,水平或垂直方向上边界(dp)
app:layout_constraintGuide_end以View的结束位置为参照物,水平或垂直方向上边界(dp)
app:layout_constraintGuide_percent水平或垂直方向上的百分比(float ratio 0.0f - 1.0f)

至此,整个ConstraintLayout的属性已讲解完毕,下面的章节我们讲分析ConstraintLayout在Android中的性能表现。让ConstraintLayout在Android中飞起来吧,Android ConstraintLayout性能分析

;