初识ConstraintLayout之链

链是一种特殊的约束。

Posted by donnieSky on September 1, 2017

翻译原文链接

什么是链

链是一种特殊的约束,它允许我们在链中的View之间共享空间,并控制View之间的空间分配。Android中LinearLayout中的weights与链有些相似之处,但链能做到更多。

创建一条链

正如我们上面所提到的,链是由多个View组成的,因此,要创建一条链,我们必须选中我们希望链接在一起的View,然后选择Center –> Center Horizontally 创建一个水平链条,或者选择–>Center Vertically创建一个垂直链条,让我们来创建一个水平链条:

chains

值得一提的是,链条末端的两个View(在这种情况下是最左边和最右边的View)已经和父布局有一个分别来自左边缘和右边缘的约束。链的创建简单的定义了链成员之间的相互关系,通过刚刚我们创建的链可以很清晰的解释这些:

chain_con

首先注意,视图之间的两个类似链条的链接(这就是我们创建的链约束),外部的两个链接(父布局与最左边和最右边之间的链接)类似于弹簧。这些最外部的链接表示已经应用于链的链模式链模式指定链条如何填充可用空间,我们可以使用循环链模式按钮在三种可用模式之间循环,该按钮显示在链的所有成员下方:

mode

一共有三种可用的模式:spreadspread_insidepacked

扩展链(Spread Chain)

spread是默认的模式,它可以在可以的空间内衣均匀的间隔在链中放置所有View

spread

内部扩展链(Spread Inside Chain)

spread_inside模式将链中最外层的View放置在外边缘,然后在可用空间内以相等的间隔放置链中的其余View:

spread_inside

包裹链(Packed Chain)

packed模式将所有View集中在一起(可以提供边距来稍微分开View之间的距离),然后将集中后的一组View居中放置在可用空间内:

packed

使用包裹链可以通过改变bias值来进一步控制包裹后View的布局位置,在以上例子中,bias值为0.5,代表居中的意思,但改变这个值可以改变包裹链的位置:

packed_mode

扩展链权重(Spread Chain Weights)

扩展链和内部扩展链的一个非常有用的功能就是我们可以将权重应用于链的各个成员,并且和LinearLayout中的权重非常相似。目前视图编辑器中没有直接设置的方法,但我们可以在属性视图中手动更改属性:

chain_weight

要给特定的View添加权重,我们必须首先在编辑器中选择view,然后(如果View是在水平链中)指定android:layout_width="0dp"app:layout_constraintHorizontal_weight="1"

attribute

请注意加权重后View的变化:顶部和底部边缘从直线变成了手风琴样式,这使加权重View有了更直观的显示。

值得注意的是,如果我们尝试在包裹模式下添加权重,这将不会很好使,包裹模式会尝试将View包裹在尽可能小的空间内,而扩展和内部扩展模式将根据需要来使用尽可能多的空间。如果尝试在包裹链中使用权重,则加权重的View将缩小到0:

packed_weight

在XML中使用链

有时候我们会在想,在XML中应该存在专有的属性来表示链,但事实并非如此:现有的约束属性都被合并了,为了在XML中创建链,链条约束是简单的双向互补约束。下面就是我们所提到的在XML中创建链:

<?xml version="1.0" encoding="utf-8"?>
<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"
    tools:layout_editor_absoluteX="0dp"
    tools:layout_editor_absoluteY="25dp">

    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginTop="16dp"
        android:text="Hello World!"
        app:layout_constraintEnd_toStartOf="@+id/textView2"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintHorizontal_chainStyle="spread"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"/>

    <TextView
        android:id="@+id/textView2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="16dp"
        android:text="Hello World!"
        app:layout_constraintEnd_toStartOf="@+id/textView3"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toEndOf="@+id/textView1"
        app:layout_constraintTop_toTopOf="parent"
        tools:layout_editor_absoluteX="154dp"/>

    <TextView
        android:id="@+id/textView3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginEnd="16dp"
        android:layout_marginTop="16dp"
        android:text="Hello World!"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toEndOf="@+id/textView2"
        app:layout_constraintTop_toTopOf="parent"/>

</android.support.constraint.ConstraintLayout>

textView1中有app:layout_constraintEndToStartOf="@+id/textView2",并且在textView2中有app:layout_constraintStart_toEndOf="@+id/textView1",基本上可以看出在这两个View右边缘和左边缘的锚点之间创建了两个约束,而这就是链的定义方法。

textView1中我们可以看到有app:layout_constraintHorizontal_chainStyle="spread",它指定了扩展模式,我们可以手动修改为:spread_insidepacked来指定不同的链模式。注意我们必须只在链中的第一个View是使用该属性

app:layout_constraintHorizontal_bias="0.5"的设置区间为0.0-1.0

最后,我们可以通过指定android:layout_width="0dp"app:layout_constraintHorizontal_weight="1"来定义权重。