Android ConstraintLayout使用詳解

前言

ConstraintLayout 是一個(gè)使用“相對(duì)定位”靈活地確定微件的位置和大小的一個(gè)布局两蟀,在 2016 年 Google I/O 中面世,它的出現(xiàn)是為了解決開發(fā)中過于復(fù)雜的頁(yè)面層級(jí)嵌套過多的問題——層級(jí)過深會(huì)增加繪制界面需要的時(shí)間私杜,影響用戶體驗(yàn)黔龟,以靈活的方式定位和調(diào)整小部件。從 Android Studio 2.3起穷蛹,創(chuàng)建layout文件就已經(jīng)是默認(rèn)ConstraintLayout了秤朗,但是盡管Google如此大力推這項(xiàng)技術(shù)煤蹭,但在當(dāng)時(shí)很少有人使用,近些年逐漸被大家拿起來取视,啊真香O踉怼(此處無圖勝有圖)。目前ConstraintLayout正式版已經(jīng)更新至2.0.4作谭,本文將帶領(lǐng)大家熟悉ConstraintLayout全部?jī)?nèi)容稽物。

轉(zhuǎn)載于Quyunshuo作者

Quyunshuo的博客地址:
https://juejin.cn/user/78820569533070/posts

布局的使用

位置約束

ConstraintLayout采用方向約束的方式對(duì)控件進(jìn)行定位,至少要保證水平和垂直方向都至少有一個(gè)約束才能確定控件的位置

  • 基本方向約束

比如我們想實(shí)現(xiàn)這個(gè)位置折欠,頂部和界面頂部對(duì)齊贝或,左部和界面左部對(duì)齊:
圖片
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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"
    android:background="#DAF3FE"
    tools:context=".MainActivity">

    <TextView
        android:layout_width="100dp"
        android:layout_height="60dp"
        android:background="@drawable/tv_bg"
        android:gravity="center"
        android:text="A"
        android:textColor="@color/black"
        android:textSize="25sp"
        android:textStyle="bold"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        tools:ignore="HardcodedText" />

</androidx.constraintlayout.widget.ConstraintLayout> </pre>

核心代碼是這兩行:
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"

這兩行代碼的意思就是,控件的開始方向與父容器的開始方向?qū)R,控件的頂部方向與父容器的頂部方向?qū)R锐秦,其實(shí)layout_constraintStart_toStartOf也可以使用layout_constraintLeft_toLeftOf咪奖,但是使用start和end來表示左和右是為了考慮別的國(guó)家的習(xí)慣,有的國(guó)家開始方向是右酱床,所以使用start和end可以兼容這種情況羊赵。到這里就可以看到該控件使用layout_constraintStart_toStartOf和layout_constraintTop_toTopOf兩條約束確定了自己的位置,這里有一個(gè)使用技巧扇谣,就是昧捷,該控件的?罐寨?方向在哪個(gè)控件的靡挥??方向鸯绿,記住這一點(diǎn)就可以了跋破。那么下面就介紹下全部的約束屬性:

基本方向約束
我的什么位置在誰(shuí)的什么位置
app:layout_constraintTop_toTopOf="" 我的頂部和誰(shuí)的頂部對(duì)齊
app:layout_constraintBottom_toBottomOf="" 我的底部和誰(shuí)的底部對(duì)齊
app:layout_constraintLeft_toLeftOf="" 我的左邊和誰(shuí)的左邊對(duì)齊
app:layout_constraintRight_toRightOf="" 我的右邊和誰(shuí)的右邊對(duì)齊
app:layout_constraintStart_toStartOf="" 我的開始位置和誰(shuí)的開始位置對(duì)齊
app:layout_constraintEnd_toEndOf="" 我的結(jié)束位置和誰(shuí)的結(jié)束位置對(duì)齊
app:layout_constraintTop_toBottomOf="" 我的頂部位置在誰(shuí)的底部位置
app:layout_constraintStart_toEndOf="" 我的開始位置在誰(shuí)的結(jié)束為止

那么ConstraintLayout就是使用這些屬性來確定控件的位置,雖然比較多楞慈,但是有規(guī)律可循幔烛,沒有任何記憶壓力

  • 基線對(duì)齊

我們看一個(gè)場(chǎng)景:
圖片

我們有時(shí)候需要寫這樣的需求:兩個(gè)文本是基線對(duì)齊的,那就可以用到我們的一個(gè)屬性layout_constraintBaseline_toBaselineOf來實(shí)現(xiàn)囊蓝,它的意思就是這個(gè)控件的基線與誰(shuí)的基線對(duì)齊,代碼如下:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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"
    android:background="#DAF3FE"
    tools:context=".MainActivity"
    tools:ignore="HardcodedText">

    <TextView
        android:id="@+id/tv1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="20"
        android:textColor="@color/black"
        android:textSize="50sp"
        android:textStyle="bold"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/tv2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="¥"
        android:textColor="@color/black"
        android:textSize="20sp"
        app:layout_constraintBaseline_toBaselineOf="@id/tv1"
        app:layout_constraintStart_toEndOf="@id/tv1" />

</androidx.constraintlayout.widget.ConstraintLayout>

通過layout_constraintBaseline_toBaselineOf我們就可以讓兩個(gè)不同大小的文案基線對(duì)齊

  • 角度約束

有些時(shí)候我們需要一個(gè)控件在某個(gè)控件的某個(gè)角度的位置令蛉,那么通過其他的布局其實(shí)是不太好實(shí)現(xiàn)的聚霜,但是ConstraintLayout為我們提供了角度位置相關(guān)的屬性
app:layout_constraintCircle="" 目標(biāo)控件id
app:layout_constraintCircleAngle="" 對(duì)于目標(biāo)的角度(0-360)
app:layout_constraintCircleRadius="" 到目標(biāo)中心的距離 </pre>

我們來實(shí)現(xiàn)一下下圖的UI狡恬,jetpack圖標(biāo)在android圖標(biāo)的45度方向,距離為60dp
圖片
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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"
    android:background="#DAF3FE"
    tools:context=".MainActivity"
    tools:ignore="HardcodedText">

    <ImageView
        android:id="@+id/android"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:src="@drawable/android"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <ImageView
        android:id="@+id/jetpack"
        android:layout_width="60dp"
        android:layout_height="60dp"
        android:src="@drawable/jetpack"
        app:layout_constraintCircle="@+id/android"
        app:layout_constraintCircleAngle="45"
        app:layout_constraintCircleRadius="70dp" />

</androidx.constraintlayout.widget.ConstraintLayout>
  • 百分比偏移

有的時(shí)候我們需要讓控件在父布局的水平方向或垂直方向的百分之多少的位置蝎宇,可以使用如下屬性:
app:layout_constraintHorizontal_bias="" 水平偏移 取值范圍是0-1的小數(shù)
app:layout_constraintVertical_bias="" 垂直偏移 取值范圍是0-1的小數(shù) </pre>

示例:控件A在父布局水平方向偏移0.3(30%)弟劲,垂直方向偏移0.8(80%)
注意:在使用百分比偏移時(shí),需要指定對(duì)應(yīng)位置的約束條件

圖片

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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"
    android:background="#DAF3FE"
    tools:context=".MainActivity"
    tools:ignore="HardcodedText">

    <TextView
        android:layout_width="100dp"
        android:layout_height="60dp"
        android:background="@drawable/tv_bg"
        android:gravity="center"
        android:text="A"
        android:textColor="@color/black"
        android:textSize="25sp"
        android:textStyle="bold"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.3"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.8" />

</androidx.constraintlayout.widget.ConstraintLayout>

控件內(nèi)邊距姥芥、外邊距兔乞、GONE Margin

ConstraintLayout的內(nèi)邊距和外邊距的使用方式其實(shí)是和其他布局一致的

外邊距
android:layout_margin="0dp"
android:layout_marginStart="0dp"
android:layout_marginLeft="0dp"
android:layout_marginTop="0dp"
android:layout_marginEnd="0dp"
android:layout_marginRight="0dp"
android:layout_marginBottom="0dp"

內(nèi)邊距
android:padding="0dp"
android:paddingStart="0dp"
android:paddingLeft="0dp"
android:paddingTop="0dp"
android:paddingEnd="0dp"
android:paddingRight="0dp"
android:paddingBottom="0dp" </pre>

ConstraintLayout除此之外還有GONE Margin,當(dāng)依賴的目標(biāo)view隱藏時(shí)會(huì)生效的屬性凉唐,例如B被A依賴約束庸追,當(dāng)B隱藏時(shí)B會(huì)縮成一個(gè)點(diǎn),自身的margin效果失效台囱,A設(shè)置的GONE Margin就會(huì)生效淡溯,屬性如下:

GONE Margin
app:layout_goneMarginBottom="0dp"
app:layout_goneMarginEnd="0dp"
app:layout_goneMarginLeft="0dp"
app:layout_goneMarginRight="0dp"
app:layout_goneMarginStart="0dp"
app:layout_goneMarginTop="0dp"

示例:當(dāng)目標(biāo)控件是顯示的時(shí)候GONE Margin不會(huì)生效
圖片
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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"
    android:background="#DAF3FE"
    tools:context=".MainActivity"
    tools:ignore="HardcodedText">

    <TextView
        android:id="@+id/A"
        android:layout_width="100dp"
        android:layout_height="60dp"
        android:layout_marginStart="100dp"
        android:layout_marginTop="100dp"
        android:background="@drawable/tv_bg"
        android:gravity="center"
        android:text="A"
        android:textColor="@color/black"
        android:textSize="25sp"
        android:textStyle="bold"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <!--  該控件設(shè)置了 layout_goneMarginStart="100dp" 當(dāng)A控件隱藏時(shí)才會(huì)生效  -->
    <TextView
        android:id="@+id/B"
        android:layout_width="60dp"
        android:layout_height="40dp"
        android:background="@drawable/tv_bg"
        android:gravity="center"
        android:text="B"
        android:textColor="@color/black"
        android:textSize="25sp"
        android:textStyle="bold"
        app:layout_constraintBottom_toBottomOf="@id/A"
        app:layout_constraintStart_toEndOf="@id/A"
        app:layout_constraintTop_toTopOf="@id/A"
        app:layout_goneMarginStart="100dp" />

</androidx.constraintlayout.widget.ConstraintLayout>

當(dāng)目標(biāo)A控件隱藏時(shí),B的GONE Margin就會(huì)生效
圖片

控件尺寸

  • 尺寸限制

在ConstraintLayout中提供了一些尺寸限制的屬性簿训,可以用來限制最大咱娶、最小寬高度,這些屬性只有在給出的寬度或高度為wrap_content時(shí)才會(huì)生效强品,比如想給寬度設(shè)置最小或最大值膘侮,那寬度就必須設(shè)置為wrap_content,這個(gè)比較簡(jiǎn)單就不放示例代碼了的榛,具體的屬性如下:

android:minWidth="" 設(shè)置view的最小寬度
android:minHeight="" 設(shè)置view的最小高度
android:maxWidth="" 設(shè)置view的最大寬度
android:maxHeight="" 設(shè)置view的最大高度

  • 0dp(MATCH_CONSTRAINT)

設(shè)置view的大小除了傳統(tǒng)的wrap_content琼了、指定尺寸、match_parent外困曙,ConstraintLayout還可以設(shè)置為0dp(MATCH_CONSTRAINT)表伦,并且0dp的作用會(huì)根據(jù)設(shè)置的類型而產(chǎn)生不同的作用,進(jìn)行設(shè)置類型的屬性是layout_constraintWidth_default和layout_constraintHeight_default慷丽,取值可為spread蹦哼、percent、wrap要糊。具體的屬性及示例如下:

app:layout_constraintWidth_default="spread|percent|wrap"
app:layout_constraintHeight_default="spread|percent|wrap" </pre>

spread(默認(rèn)):占用所有的符合約束的空間

圖片

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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"
    android:background="#DAF3FE"
    tools:context=".MainActivity"
    tools:ignore="HardcodedText">

    <TextView
        android:id="@+id/A"
        android:layout_width="0dp"
        android:layout_height="60dp"
        android:layout_marginStart="50dp"
        android:layout_marginTop="50dp"
        android:layout_marginEnd="50dp"
        android:background="@drawable/tv_bg"
        android:gravity="center"
        android:text="A"
        android:textColor="@color/black"
        android:textSize="25sp"
        android:textStyle="bold"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintWidth_default="spread" />

</androidx.constraintlayout.widget.ConstraintLayout> 

可以看到纲熏,view的寬度適應(yīng)了所有有效的約束空間,左右留出了margin的設(shè)置值50dp锄俄,這種效果就就是:自身view的大小充滿可以配置的剩余空間局劲,因?yàn)樽笥壹s束的都是父布局,所以view可配置的空間是整個(gè)父布局的寬度奶赠,又因?yàn)樵O(shè)置了margin鱼填,所以會(huì)留出margin的大小,因?yàn)閟pread是默認(rèn)值毅戈,所以可以不寫 app:layout_constraintWidth_default="spread"苹丸。

percent:按照父布局的百分比設(shè)置

圖片

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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"
    android:background="#DAF3FE"
    tools:context=".MainActivity"
    tools:ignore="HardcodedText">

    <TextView
        android:id="@+id/A"
        android:layout_width="0dp"
        android:layout_height="60dp"
        android:layout_marginTop="50dp"
        android:background="@drawable/tv_bg"
        android:gravity="center"
        android:text="A"
        android:textColor="@color/black"
        android:textSize="25sp"
        android:textStyle="bold"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintWidth_default="percent"
        app:layout_constraintWidth_percent="0.5" />

</androidx.constraintlayout.widget.ConstraintLayout> 

percent模式的意思是自身view的尺寸是父布局尺寸的一定比例愤惰,上圖所展示的是寬度是父布局寬度的0.5(50%,取值是0-1的小數(shù))赘理,該模式需要配合layout_constraintWidth_percent使用宦言,但是寫了layout_constraintWidth_percent后,layout_constraintWidth_default="percent"其實(shí)就可以省略掉了商模。

wrap:匹配內(nèi)容大小但不超過約束限制

圖片

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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"
    android:background="#DAF3FE"
    tools:context=".MainActivity"
    tools:ignore="HardcodedText">

    <!--  寬度設(shè)置為wrap_content  -->
    <TextView
        android:id="@+id/A"
        android:layout_width="wrap_content"
        android:layout_height="60dp"
        android:layout_marginStart="100dp"
        android:layout_marginTop="50dp"
        android:layout_marginEnd="100dp"
        android:background="@drawable/tv_bg"
        android:gravity="center"
        android:text="AAAAAAAAAAAAAAAAAA"
        android:textColor="@color/black"
        android:textSize="25sp"
        android:textStyle="bold"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintWidth_default="spread" />

    <!--  寬度設(shè)置為0dp wrap模式  -->
    <TextView
        android:id="@+id/B"
        android:layout_width="0dp"
        android:layout_height="60dp"
        android:layout_marginStart="100dp"
        android:layout_marginTop="150dp"
        android:layout_marginEnd="100dp"
        android:background="@drawable/tv_bg"
        android:gravity="center"
        android:text="BBBBBBBBBBBBBBBBBBBBBBB"
        android:textColor="@color/black"
        android:textSize="25sp"
        android:textStyle="bold"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintWidth_default="wrap" />

</androidx.constraintlayout.widget.ConstraintLayout> 

這里寫了兩個(gè)控件作為對(duì)比奠旺,控件A寬度設(shè)置為wrap_content购裙,寬度適應(yīng)內(nèi)容大小旱爆,并且設(shè)置了margin,但是顯然寬度已經(jīng)超過margin的設(shè)置值了洞渔,而控件B寬度設(shè)置為0dp wrap模式嫂沉,寬度適應(yīng)內(nèi)容大小稽寒,并且不會(huì)超過margin的設(shè)置值,也就是不會(huì)超過約束限制趟章,這就是這兩者的區(qū)別杏糙。Google還提供了兩個(gè)屬性用于強(qiáng)制約束:

當(dāng)一個(gè)view的寬或高,設(shè)置成wrap_content時(shí)
app:layout_constrainedWidth="true|false"
app:layout_constrainedHeight="true|false"

還是上一個(gè)例子,這里將控件A設(shè)置了強(qiáng)制約束蚓土,展示出的效果和控件B是一樣的了:
圖片
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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"
    android:background="#DAF3FE"
    tools:context=".MainActivity"
    tools:ignore="HardcodedText">

    <TextView
        android:id="@+id/A"
        android:layout_width="wrap_content"
        android:layout_height="60dp"
        android:layout_marginStart="100dp"
        android:layout_marginTop="50dp"
        android:layout_marginEnd="100dp"
        android:background="@drawable/tv_bg"
        android:gravity="center"
        android:text="AAAAAAAAAAAAAAAAAA"
        android:textColor="@color/black"
        android:textSize="25sp"
        android:textStyle="bold"
        app:layout_constrainedWidth="true"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintWidth_default="spread" />

</androidx.constraintlayout.widget.ConstraintLayout> 

除此之外宏侍,0dp還有一些其他的獨(dú)特屬性用于設(shè)置尺寸的大小限制
app:layout_constraintWidth_min="" 0dp下,寬度的最小值
app:layout_constraintHeight_min="" 0dp下蜀漆,高度的最小值
app:layout_constraintWidth_max="" 0dp下谅河,寬度的最大值
app:layout_constraintHeight_max="" 0dp下,高度的最大值 </pre>

  • 比例寬高(Ratio)

ConstraintLayout中可以對(duì)寬高設(shè)置比例确丢,前提是至少有一個(gè)約束維度設(shè)置為0dp绷耍,這樣比例才會(huì)生效,該屬性可使用兩種設(shè)置:
1. 浮點(diǎn)值鲜侥,表示寬度和高度之間的比率
2. 寬度:高度褂始,表示寬度和高度之間形式的比率
app:layout_constraintDimensionRatio="" 寬高比例

圖片
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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"
    android:background="#DAF3FE"
    tools:context=".MainActivity"
    tools:ignore="HardcodedText">

    <TextView
        android:id="@+id/A"
        android:layout_width="0dp"
        android:layout_height="100dp"
        android:background="@drawable/tv_bg"
        android:gravity="center"
        android:text="A"
        android:textColor="@color/black"
        android:textSize="25sp"
        android:textStyle="bold"
        app:layout_constraintDimensionRatio="1:1"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout> 

Chains(鏈)

Chains(鏈)也是一個(gè)非常好用的特性,它是將許多個(gè)控件在水平或者垂直方向描函,形成一條鏈崎苗,用于平衡這些控件的位置,那么如何形成一條鏈呢舀寓?形成一條鏈要求鏈中的控件在水平或者垂直方向胆数,首尾互相約束,這樣就可以形成一條鏈互墓,水平方向互相約束形成的就是一條水平鏈必尼,反之則是垂直鏈,下面看示例:
圖片
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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"
    android:background="#DAF3FE"
    tools:context=".MainActivity"
    tools:ignore="HardcodedText">

    <TextView
        android:id="@+id/A"
        android:layout_width="80dp"
        android:layout_height="80dp"
        android:background="@drawable/tv_bg"
        android:gravity="center"
        android:text="A"
        android:textColor="@color/black"
        android:textSize="25sp"
        android:textStyle="bold"
        app:layout_constraintEnd_toStartOf="@id/B"
        app:layout_constraintHorizontal_chainStyle="spread"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/B"
        android:layout_width="80dp"
        android:layout_height="80dp"
        android:background="@drawable/tv_bg"
        android:gravity="center"
        android:text="B"
        android:textColor="@color/black"
        android:textSize="25sp"
        android:textStyle="bold"
        app:layout_constraintEnd_toStartOf="@id/C"
        app:layout_constraintStart_toEndOf="@id/A"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/C"
        android:layout_width="80dp"
        android:layout_height="80dp"
        android:background="@drawable/tv_bg"
        android:gravity="center"
        android:text="C"
        android:textColor="@color/black"
        android:textSize="25sp"
        android:textStyle="bold"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@id/B"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

A篡撵、B胰伍、C齿诞,三個(gè)控件在水平方向上首尾互相約束酸休,這樣就形成了一條水平鏈骂租,他們默認(rèn)的模式是spread,均分剩余空間斑司,我們可以使用layout_constraintHorizontal_chainStyle和layout_constraintVertical_chainStyle分別對(duì)水平和垂直鏈設(shè)置模式渗饮,模式可選的值有:spread、packed宿刮、spread_inside
圖片
圖片
圖片

Chains(鏈)還支持weight(權(quán)重)的配置互站,使用layout_constraintHorizontal_weight和layout_constraintVertical_weight進(jìn)行設(shè)置鏈元素的權(quán)重
圖片
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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"
    android:background="#DAF3FE"
    tools:context=".MainActivity"
    tools:ignore="HardcodedText">

    <TextView
        android:id="@+id/A"
        android:layout_width="0dp"
        android:layout_height="80dp"
        android:background="@drawable/tv_bg"
        android:gravity="center"
        android:text="A"
        android:textColor="@color/black"
        android:textSize="25sp"
        android:textStyle="bold"
        app:layout_constraintEnd_toStartOf="@id/B"
        app:layout_constraintHorizontal_weight="2"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_chainStyle="packed" />

    <TextView
        android:id="@+id/B"
        android:layout_width="0dp"
        android:layout_height="80dp"
        android:background="@drawable/tv_bg"
        android:gravity="center"
        android:text="B"
        android:textColor="@color/black"
        android:textSize="25sp"
        android:textStyle="bold"
        app:layout_constraintEnd_toStartOf="@id/C"
        app:layout_constraintHorizontal_weight="1"
        app:layout_constraintStart_toEndOf="@id/A"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/C"
        android:layout_width="0dp"
        android:layout_height="80dp"
        android:background="@drawable/tv_bg"
        android:gravity="center"
        android:text="C"
        android:textColor="@color/black"
        android:textSize="25sp"
        android:textStyle="bold"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_weight="3"
        app:layout_constraintStart_toEndOf="@id/B"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

輔助類

ConstraintLayout為了解決嵌套問題還提供了一系列的輔助控件幫助開發(fā)者布局,這些工具十分的方便僵缺,我在日常開發(fā)工作中也是使用的非常頻繁

Guideline(參考線)

Guideline是一條參考線胡桃,可以幫助開發(fā)者進(jìn)行輔助定位,并且實(shí)際上它并不會(huì)真正顯示在布局中磕潮,像是數(shù)學(xué)幾何中的輔助線一樣翠胰,使用起來十分方便,出場(chǎng)率很高自脯,Guideline也可以用來做一些百分比分割之類的需求之景,有著很好的屏幕適配效果,Guideline有水平和垂直方向之分膏潮,位置可以使用針對(duì)父級(jí)的百分比或者針對(duì)父級(jí)位置的距離

android:orientation="horizontal|vertical" 輔助線的對(duì)齊方式
app:layout_constraintGuide_percent="0-1" 距離父級(jí)寬度或高度的百分比(小數(shù)形式)
app:layout_constraintGuide_begin="" 距離父級(jí)起始位置的距離(左側(cè)或頂部)
app:layout_constraintGuide_end="" 距離父級(jí)結(jié)束位置的距離(右側(cè)或底部)

圖片
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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"
    android:background="#DAF3FE"
    tools:context=".MainActivity"
    tools:ignore="HardcodedText">

    <androidx.constraintlayout.widget.Guideline
        android:id="@+id/Guideline"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        app:layout_constraintGuide_percent="0.5" />

    <TextView
        android:id="@+id/A"
        android:layout_width="120dp"
        android:layout_height="80dp"
        android:background="@drawable/tv_bg"
        android:gravity="center"
        android:text="A"
        android:textColor="@color/black"
        android:textSize="25sp"
        android:textStyle="bold"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="@id/Guideline" />

</androidx.constraintlayout.widget.ConstraintLayout>

上圖中設(shè)置了一條水平方向位置在父級(jí)垂直方向0.5(50%)的Guideline锻狗,控件A的頂部依賴于Guideline,這樣無論布局如何更改焕参,Guideline的位置始終都會(huì)是父級(jí)垂直方向50%的位置轻纪,控件A的位置也不會(huì)偏離預(yù)設(shè)

Barrier(屏障)

這個(gè)Barrier和Guideline一樣,也不會(huì)實(shí)際出現(xiàn)在布局中叠纷,它的作用如同其名刻帚,形成一個(gè)屏障、障礙讲岁,使用也非常多我擂。這里借助constraintlayout網(wǎng)站(https://constraintlayout.github.io/basics/barriers.html)來講解Barrier。 當(dāng)我們創(chuàng)建布局時(shí)缓艳,有時(shí)會(huì)遇到布局可以根據(jù)本地化而更改的情況校摩。這里借助有一個(gè)非常簡(jiǎn)單的例子:

圖片

這里有三個(gè)文本視圖:左邊的textView1和textView2;右邊的textView3阶淘。textView3被限制在textView1的末尾衙吩,這工作得很好——它完全根據(jù)我們需要來定位和大小textView3。然而溪窒,如果我們需要支持多種語(yǔ)言坤塞,事情會(huì)變得更加復(fù)雜冯勉。如果我們添加德語(yǔ)翻譯,那么我們就會(huì)遇到一個(gè)問題摹芙,因?yàn)樵谟⑽陌姹局凶普瑃extView1中的文本比textView2中的文本長(zhǎng),而在德語(yǔ)中浮禾,textView2中的文本比textView1長(zhǎng):
圖片

這里的問題在于textView3仍然是相對(duì)于textView1的交胚,所以textView2直接插入了textView3中。在設(shè)計(jì)視圖里看起來更明顯(白色背景的那個(gè))盈电。比較直接的解決辦法是使用TableLayout蝴簇,或者把 textView1 & textView2 包裹在一個(gè)垂直的,android:layout_width="wrap_content" 的 LinearLayout中匆帚。然后讓textView3約束在這個(gè)LinearLayout的后面熬词。但是我們有更好的辦法:Barriers。Barriers的配置屬性如下:

用于控制Barrier相對(duì)于給定的View的位置
app:barrierDirection="top|bottom|left|right|start|end"
取值是要依賴的控件的id吸重,Barrier將會(huì)使用ids中最大的一個(gè)的寬/高作為自己的位置
app:constraint_referenced_ids="id,id" </pre>

修改過后的代碼如下:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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">

    <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="@string/warehouse"
        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_marginStart="16dp"
        android:layout_marginTop="8dp"
        android:text="@string/hospital"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/textView1" />

    <androidx.constraintlayout.widget.Barrier
        android:id="@+id/barrier7"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:barrierDirection="end"
        app:constraint_referenced_ids="textView2,textView1" />

    <TextView
        android:id="@+id/textView3"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:text="@string/lorem_ipsum"
        app:layout_constraintStart_toEndOf="@+id/barrier7"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>
圖片

為了看到整體的效果互拾,可以切換語(yǔ)言,此時(shí)你會(huì)看到Barrier會(huì)自動(dòng)位于較寬的那個(gè)textView后面晤锹,也就間接讓textView3也位于了正確的位置摩幔。

Group(組)

工作當(dāng)中常常會(huì)有很多個(gè)控件同時(shí)隱藏或者顯示的場(chǎng)景,傳統(tǒng)做法要么是進(jìn)行嵌套鞭铆,對(duì)父布局進(jìn)行隱藏或顯示或衡,要么就是一個(gè)一個(gè)設(shè)置,這顯然都不是很好的辦法车遂,ConstraintLayout中的Group就是來解決這個(gè)問題的封断。Group的作用就是可以對(duì)一組控件同時(shí)隱藏或顯示,沒有其他的作用舶担,它的屬性如下:

app:constraint_referenced_ids="id,id" 加入組的控件id

圖片
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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"
    android:background="#DAF3FE"
    tools:context=".MainActivity"
    tools:ignore="HardcodedText">

    <TextView
        android:id="@+id/A"
        android:layout_width="100dp"
        android:layout_height="60dp"
        android:layout_marginTop="56dp"
        android:background="@drawable/tv_bg"
        android:gravity="center"
        android:text="A"
        android:textColor="@color/black"
        android:textSize="25sp"
        android:textStyle="bold"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.115"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/B"
        android:layout_width="100dp"
        android:layout_height="60dp"
        android:layout_marginTop="280dp"
        android:background="@drawable/tv_bg"
        android:gravity="center"
        android:text="B"
        android:textColor="@color/black"
        android:textSize="25sp"
        android:textStyle="bold"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.758"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/C"
        android:layout_width="100dp"
        android:layout_height="60dp"
        android:layout_marginTop="164dp"
        android:background="@drawable/tv_bg"
        android:gravity="center"
        android:text="C"
        android:textColor="@color/black"
        android:textSize="25sp"
        android:textStyle="bold"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.437"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <androidx.constraintlayout.widget.Group
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:visibility="visible"
        app:constraint_referenced_ids="A,B,C" />

</androidx.constraintlayout.widget.ConstraintLayout> 

A坡疼、B、C三個(gè)view衣陶,受Group控制柄瑰,當(dāng)Group的visibility為visible時(shí),它們都是正常顯示的剪况,設(shè)置為gone時(shí)教沾,它們都會(huì)隱藏:
圖片

Placeholder(占位符)

Placeholder的作用就是占位,它可以在布局中占好位置译断,通過app:content=""屬性授翻,或者動(dòng)態(tài)調(diào)用setContent()設(shè)置內(nèi)容,來讓某個(gè)控件移動(dòng)到此占位符中
圖片
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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"
    android:background="#DAF3FE"
    tools:context=".MainActivity"
    tools:ignore="HardcodedText">

    <TextView
        android:id="@+id/A"
        android:layout_width="100dp"
        android:layout_height="60dp"
        android:background="@drawable/tv_bg"
        android:gravity="center"
        android:text="A"
        android:textColor="@color/black"
        android:textSize="25sp"
        android:textStyle="bold"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <androidx.constraintlayout.widget.Placeholder
        android:layout_width="100dp"
        android:layout_height="60dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout> 

當(dāng)我們?cè)O(shè)置app:content="@+id/A"或者調(diào)用setContent()時(shí),控件A就會(huì)被移動(dòng)到Placeholder中堪唐,當(dāng)然在布局中使用app:content=""顯然就失去了它的作用巡语。

Flow(流式虛擬布局)

Flow是用于構(gòu)建鏈的新虛擬布局,當(dāng)鏈用完時(shí)可以纏繞到下一行甚至屏幕的另一部分淮菠。當(dāng)您在一個(gè)鏈中布置多個(gè)項(xiàng)目時(shí)男公,這很有用,但是您不確定容器在運(yùn)行時(shí)的大小兜材。您可以使用它來根據(jù)應(yīng)用程序中的動(dòng)態(tài)尺寸(例如旋轉(zhuǎn)時(shí)的屏幕寬度)構(gòu)建布局理澎。Flow是一種虛擬布局。在ConstraintLayout中曙寡,虛擬布局(Virtual layouts)作為virtual view group的角色參與約束和布局中,但是它們并不會(huì)作為視圖添加到視圖層級(jí)結(jié)構(gòu)中寇荧,而是僅僅引用其它視圖來輔助它們?cè)诓季窒到y(tǒng)中完成各自的布局功能举庶。下面使用動(dòng)畫來展示Flow創(chuàng)建多個(gè)鏈將布局元素充裕地填充一整行:
圖片
圖片
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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"
    android:background="#DAF3FE"
    tools:context=".MainActivity"
    tools:ignore="HardcodedText">

    <TextView
        android:id="@+id/A"
        android:layout_width="60dp"
        android:layout_height="60dp"
        android:background="@drawable/tv_bg"
        android:gravity="center"
        android:text="A"
        android:textColor="@color/black"
        android:textSize="25sp"
        android:textStyle="bold" />

    <TextView
        android:id="@+id/B"
        android:layout_width="60dp"
        android:layout_height="60dp"
        android:background="@drawable/tv_bg"
        android:gravity="center"
        android:text="B"
        android:textColor="@color/black"
        android:textSize="25sp"
        android:textStyle="bold" />

    <TextView
        android:id="@+id/C"
        android:layout_width="60dp"
        android:layout_height="60dp"
        android:background="@drawable/tv_bg"
        android:gravity="center"
        android:text="C"
        android:textColor="@color/black"
        android:textSize="25sp"
        android:textStyle="bold" />

    <TextView
        android:id="@+id/D"
        android:layout_width="60dp"
        android:layout_height="60dp"
        android:background="@drawable/tv_bg"
        android:gravity="center"
        android:text="D"
        android:textColor="@color/black"
        android:textSize="25sp"
        android:textStyle="bold" />

    <TextView
        android:id="@+id/E"
        android:layout_width="60dp"
        android:layout_height="60dp"
        android:background="@drawable/tv_bg"
        android:gravity="center"
        android:text="E"
        android:textColor="@color/black"
        android:textSize="25sp"
        android:textStyle="bold" />

    <androidx.constraintlayout.helper.widget.Flow
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:constraint_referenced_ids="A,B,C,D,E"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>
  • 鏈約束

Flow的constraint_referenced_ids關(guān)聯(lián)的控件是沒有設(shè)置約束的,這一點(diǎn)和普通的鏈?zhǔn)遣灰粯拥目眨@種排列方式是Flow的默認(rèn)方式none户侥,我們可以使用app:flow_wrapMode=""屬性來設(shè)置排列方式,并且我們還可以使用flow_horizontalGap和flow_verticalGap分別設(shè)置兩個(gè)view在水平和垂直方向的間隔峦嗤,下面我們?cè)偬砑訋讉€(gè)控件來展示三種排列方式:
圖片
圖片
圖片

下面使用動(dòng)畫來展示三種效果的變化
image.gif

當(dāng)flow_wrapMode的值是chian或aligned時(shí)蕊唐,我們還可以針對(duì)不同的鏈進(jìn)行配置,這里就不一一展示效果了烁设,具體的屬性如下:

app:flow_horizontalStyle="packed|spread|spread_inside" 所有水平鏈的配置
app:flow_verticalStyle="packed|spread|spread_inside" 所有垂直鏈的配置
app:flow_firstHorizontalStyle="packed|spread|spread_inside" 第一條水平鏈的配置替梨,其他條不生效
app:flow_firstVerticalStyle="packed|spread|spread_inside" 第一條垂直鏈的配置,其他條不生效
app:flow_lastHorizontalStyle="packed|spread|spread_inside" 最后一條水平鏈的配置装黑,其他條不生效
app:flow_lastVerticalStyle="packed|spread|spread_inside" 最后一條垂直鏈的配置副瀑,其他條不生效

  • 對(duì)齊約束

上面展示的都是相同大小的view,那么不同大小view的對(duì)齊方式恋谭,F(xiàn)low也提供了相應(yīng)的屬性進(jìn)行配置(flow_wrapMode="aligned"時(shí)糠睡,我試著沒有效果)

top:頂對(duì)齊、bottom:底對(duì)齊疚颊、center:中心對(duì)齊狈孔、baseline:基線對(duì)齊
app:flow_verticalAlign="top|bottom|c(diǎn)enter|baseline"
start:開始對(duì)齊、end:結(jié)尾對(duì)齊材义、center:中心對(duì)齊
app:flow_horizontalAlign="start|end|center" </pre>

使用flow_verticalAlign時(shí)均抽,要求orientation的方向是horizontal,而使用flow_horizontalAlign時(shí)母截,要求orientation的方向是vertical下面展示下各個(gè)效果:
圖片
<androidx.constraintlayout.helper.widget.Flow
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="horizontal"
        app:constraint_referenced_ids="A,B,C,D,E,F,G,H,I,J"
        app:flow_verticalAlign="top"
        app:flow_wrapMode="chain"
        app:layout_constraintTop_toTopOf="parent" /> 
圖片
<androidx.constraintlayout.helper.widget.Flow
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="horizontal"
        app:constraint_referenced_ids="A,B,C,D,E,F,G,H,I,J"
        app:flow_verticalAlign="bottom"
        app:flow_wrapMode="chain"
        app:layout_constraintTop_toTopOf="parent" /> 
圖片
<androidx.constraintlayout.helper.widget.Flow
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="horizontal"
        app:constraint_referenced_ids="A,B,C,D,E,F,G,H,I,J"
        app:flow_verticalAlign="center"
        app:flow_wrapMode="chain"
        app:layout_constraintTop_toTopOf="parent" /> 
圖片
<androidx.constraintlayout.helper.widget.Flow
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="horizontal"
        app:constraint_referenced_ids="A,B,C,D,E,F,G,H,I,J"
        app:flow_verticalAlign="baseline"
        app:flow_wrapMode="chain"
        app:layout_constraintTop_toTopOf="parent" />

垂直方向排列這里就不再作過多的展示了

  • 數(shù)量約束

當(dāng)flow_wrapMode屬性為aligned和chian時(shí)到忽,通過flow_maxElementsWrap屬性控制每行最大的子View數(shù)量,例如我們?cè)O(shè)置為flow_maxElementsWrap=4,效果圖如下:
圖片

Layer(層布局)

Layer繼承自ConstraintHelper喘漏,是一個(gè)約束助手护蝶,相對(duì)于Flow來說,Layer的使用較為簡(jiǎn)單翩迈,常用來增加背景持灰,或者共同動(dòng)畫,圖層 (Layer) 在布局期間會(huì)調(diào)整大小负饲,其大小會(huì)根據(jù)其引用的所有視圖進(jìn)行調(diào)整堤魁,代碼的先后順序也會(huì)決定著它的位置,如果代碼在所有引用view的最后面返十,那么它就會(huì)在所有view的最上面妥泉,反之則是最下面,在最上面的時(shí)候如果添加背景洞坑,就會(huì)把引用的view覆蓋掉盲链,下面展示下添加背景的例子,做動(dòng)畫的例子這里不再展示了
圖片
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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"
    android:background="#DAF3FE"
    tools:context=".MainActivity"
    tools:ignore="HardcodedText">

    <androidx.constraintlayout.helper.widget.Layer
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@drawable/common_rect_white_100_10"
        android:padding="10dp"
        app:constraint_referenced_ids="AndroidImg,NameTv" />

    <ImageView
        android:id="@+id/AndroidImg"
        android:layout_width="200dp"
        android:layout_height="wrap_content"
        android:src="@drawable/android"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/NameTv"
        android:layout_width="100dp"
        android:layout_height="40dp"
        android:gravity="center"
        android:text="Android"
        android:textColor="@color/black"
        android:textSize="25sp"
        android:textStyle="bold"
        app:layout_constraintEnd_toEndOf="@id/AndroidImg"
        app:layout_constraintStart_toStartOf="@id/AndroidImg"
        app:layout_constraintTop_toBottomOf="@id/AndroidImg" />

</androidx.constraintlayout.widget.ConstraintLayout>

可以看到迟杂,當(dāng)Layer的代碼在所有引用view的上面時(shí)刽沾,效果是正常的,因?yàn)榇藭r(shí)所有的view都在Layer的上面排拷,下面我們來看一下Layer代碼在最后面時(shí)的情況:
圖片
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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"
    android:background="#DAF3FE"
    tools:context=".MainActivity"
    tools:ignore="HardcodedText">

    <ImageView
        android:id="@+id/AndroidImg"
        android:layout_width="200dp"
        android:layout_height="wrap_content"
        android:src="@drawable/android"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/NameTv"
        android:layout_width="100dp"
        android:layout_height="40dp"
        android:gravity="center"
        android:text="Android"
        android:textColor="@color/black"
        android:textSize="25sp"
        android:textStyle="bold"
        app:layout_constraintEnd_toEndOf="@id/AndroidImg"
        app:layout_constraintStart_toStartOf="@id/AndroidImg"
        app:layout_constraintTop_toBottomOf="@id/AndroidImg" />

    <androidx.constraintlayout.helper.widget.Layer
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@drawable/common_rect_white_100_10"
        android:padding="10dp"
        app:constraint_referenced_ids="AndroidImg,NameTv" />

</androidx.constraintlayout.widget.ConstraintLayout> 

我們可以看到侧漓,此時(shí)Layer已經(jīng)把所有的view覆蓋住了

ImageFilterButton & ImageFilterView

ImageFilterButton和ImageFilterView是兩個(gè)控件,他們之間的關(guān)系就和ImageButton與ImageView是一樣的监氢,所以這里就只拿ImageFilterView來做講解布蔗。從名字上來看,它們的定位是和過濾有關(guān)系的忙菠,它們的大致作用有兩部分何鸡,一是可以用來做圓角圖片,二是可以疊加圖片資源進(jìn)行混合過濾牛欢,下面一一展示:

  • 圓角圖片

ImageFilterButton和ImageFilterView可以使用兩個(gè)屬性來設(shè)置圖片資源的圓角骡男,分別是roundPercent和round,roundPercent接受的值類型是0-1的小數(shù)傍睹,根據(jù)數(shù)值的大小會(huì)使圖片在方形和圓形之間按比例過度隔盛,round=可以設(shè)置具體圓角的大小,我在使用的過程中發(fā)現(xiàn)我的AndroidStudio拾稳,沒有這兩個(gè)屬性的代碼提示吮炕,也沒有預(yù)覽效果,但是運(yùn)行起來是有效果的访得,可能是沒有做好優(yōu)化吧龙亲。最近很熱門的一個(gè)話題陕凹,小米花費(fèi)200萬設(shè)計(jì)的新logo,我們拿來做做例子:
圖片
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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"
    android:background="#DAF3FE"
    tools:context=".MainActivity"
    tools:ignore="HardcodedText">

    <androidx.constraintlayout.utils.widget.ImageFilterView
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:src="@drawable/mi"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:roundPercent="0.7" />

</androidx.constraintlayout.widget.ConstraintLayout> 

雖然和小米新logo的圓弧不太一樣鳄炉,不過這也不是我們考慮的地方杜耙,可以看到我們使用roundPercent設(shè)置了圓角為0.7(70%),實(shí)現(xiàn)一個(gè)圓角圖片就是如此簡(jiǎn)單拂盯。

  • 圖片過濾

ImageFilterButton和ImageFilterView不但可以使用src來設(shè)置圖片資源佑女,還可以使用altSrc來設(shè)置第二個(gè)圖片資源,altSrc提供的資源將會(huì)和src提供的資源通過crossfade屬性形成交叉淡化效果,默認(rèn)情況下谈竿,crossfade=0团驱,altSrc所引用的資源不可見,取值在0-1空凸。下面看例子:
圖片
圖片
圖片

除此之外嚎花,warmth屬性可以用來調(diào)節(jié)色溫,brightness屬性用來調(diào)節(jié)亮度劫恒,saturation屬性用來調(diào)節(jié)飽和度贩幻,contrast屬性用來調(diào)節(jié)對(duì)比度,下面展示一下各自屬性和取值的效果:
圖片

MockView

你家產(chǎn)品經(jīng)理經(jīng)常會(huì)給你畫原型圖两嘴,但這絕對(duì)不是他們的專屬,我們也有自己的原型圖族壳,一個(gè)成熟的程序員要學(xué)會(huì)給自己的產(chǎn)品經(jīng)理畫大餅憔辫,我們可以使用MockView來充當(dāng)原型圖,下面看例子:
圖片
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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"
    android:background="#DAF3FE"
    tools:context=".MainActivity"
    tools:ignore="HardcodedText">

    <androidx.constraintlayout.utils.widget.MockView
        android:id="@+id/Avatar"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:layout_marginStart="80dp"
        android:layout_marginTop="100dp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <androidx.constraintlayout.utils.widget.MockView
        android:id="@+id/Name"
        android:layout_width="100dp"
        android:layout_height="30dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@id/Avatar"
        app:layout_constraintTop_toTopOf="@id/Avatar" />

    <androidx.constraintlayout.utils.widget.MockView
        android:id="@+id/Age"
        android:layout_width="100dp"
        android:layout_height="30dp"
        app:layout_constraintBottom_toBottomOf="@id/Avatar"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@id/Avatar" />

</androidx.constraintlayout.widget.ConstraintLayout>

ConstraintProperties(流式API)

2.0 提供了ConstraintProperties可以使用流式 API修改屬性

val properties = ConstraintProperties(findViewById(R.id.image))
    properties.translationZ(32f)
          .margin(ConstraintSet.START, 43)
          .apply()

MotionLayout

Motion Layout是Constraint Layout 2.0中最令人期待的功能之一仿荆。它提供了一個(gè)豐富的動(dòng)畫系統(tǒng)來協(xié)調(diào)多個(gè)視圖之間的動(dòng)畫效果贰您。MotionLayout基于ConstraintLayout,并在其之上進(jìn)行了擴(kuò)展拢操,允許您在多組約束 (或者ConstraintSets) 之間進(jìn)行動(dòng)畫的處理锦亦。您可以對(duì)視圖的移動(dòng)、滾動(dòng)令境、縮放杠园、旋轉(zhuǎn)、淡入淡出等一系列動(dòng)畫行為進(jìn)行自定義舔庶,甚至可以定義各個(gè)動(dòng)畫本身的自定義屬性抛蚁。它還可以處理手勢(shì)操作所產(chǎn)生的物理移動(dòng)效果,以及控制動(dòng)畫的速度惕橙。使用MotionLayout構(gòu)建的動(dòng)畫是可追溯且可逆的瞧甩,這意味著您可以隨意切換到動(dòng)畫過程中任意一個(gè)點(diǎn),甚至可以倒著執(zhí)行動(dòng)畫效果弥鹦。Android Studio集成了 Motion Editor(動(dòng)作編輯器)肚逸,可以利用它來操作MotionLayout對(duì)動(dòng)畫進(jìn)行生成、預(yù)覽和編輯等操作。這樣一來朦促,在協(xié)調(diào)多個(gè)視圖的動(dòng)畫時(shí)膝晾,就可以做到對(duì)各個(gè)細(xì)節(jié)進(jìn)行精細(xì)操控。由于我自己也沒有用過思灰,且說起來篇幅也挺大玷犹,這里就不再講解MotionLayout(主要是我也不會(huì))/ 結(jié)語(yǔ) /至此,關(guān)于Constraint Layout的內(nèi)容基本已經(jīng)介紹完畢洒疚,因?yàn)閮?nèi)容較多歹颓,代碼示例代碼和圖片也比較多,一次性看完實(shí)屬不易油湖,可以點(diǎn)擊收藏供以后翻閱巍扛,寫這篇文章我是經(jīng)歷了無數(shù)次放棄和重新拾起,內(nèi)容確實(shí)太多了乏德,再加上也已經(jīng)有很多不錯(cuò)的博文來介紹Constraint Layout撤奸,但是他們的肯定沒有我的全!??如有錯(cuò)誤請(qǐng)及時(shí)聯(lián)系我喊括,我會(huì)盡快修改更正胧瓜。

新小夢(mèng):Constraintlayout 2.0:你們要的更新來了https://juejin.cn/post/6854573221312725000

谷歌開發(fā)者:Constraint Layout 2.0 用法詳解https://zhuanlan.zhihu.com/p/336387890

constraintlayout網(wǎng)站https://constraintlayout.com/basics/barriers.html

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市郑什,隨后出現(xiàn)的幾起案子府喳,更是在濱河造成了極大的恐慌,老刑警劉巖蘑拯,帶你破解...
    沈念sama閱讀 211,423評(píng)論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件钝满,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡申窘,警方通過查閱死者的電腦和手機(jī)弯蚜,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,147評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來剃法,“玉大人碎捺,你說我怎么就攤上這事⌒眩” “怎么了牵寺?”我有些...
    開封第一講書人閱讀 157,019評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)恩脂。 經(jīng)常有香客問我帽氓,道長(zhǎng),這世上最難降的妖魔是什么俩块? 我笑而不...
    開封第一講書人閱讀 56,443評(píng)論 1 283
  • 正文 為了忘掉前任黎休,我火速辦了婚禮浓领,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘势腮。我一直安慰自己联贩,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,535評(píng)論 6 385
  • 文/花漫 我一把揭開白布捎拯。 她就那樣靜靜地躺著泪幌,像睡著了一般。 火紅的嫁衣襯著肌膚如雪署照。 梳的紋絲不亂的頭發(fā)上祸泪,一...
    開封第一講書人閱讀 49,798評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音建芙,去河邊找鬼没隘。 笑死,一個(gè)胖子當(dāng)著我的面吹牛禁荸,可吹牛的內(nèi)容都是我干的右蒲。 我是一名探鬼主播,決...
    沈念sama閱讀 38,941評(píng)論 3 407
  • 文/蒼蘭香墨 我猛地睜開眼赶熟,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼瑰妄!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起映砖,我...
    開封第一講書人閱讀 37,704評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤翰撑,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后啊央,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,152評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡涨醋,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,494評(píng)論 2 327
  • 正文 我和宋清朗相戀三年瓜饥,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片浴骂。...
    茶點(diǎn)故事閱讀 38,629評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡乓土,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出溯警,到底是詐尸還是另有隱情趣苏,我是刑警寧澤,帶...
    沈念sama閱讀 34,295評(píng)論 4 329
  • 正文 年R本政府宣布梯轻,位于F島的核電站食磕,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏喳挑。R本人自食惡果不足惜彬伦,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,901評(píng)論 3 313
  • 文/蒙蒙 一滔悉、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧单绑,春花似錦回官、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,742評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至区转,卻和暖如春苔巨,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背蜗帜。 一陣腳步聲響...
    開封第一講書人閱讀 31,978評(píng)論 1 266
  • 我被黑心中介騙來泰國(guó)打工恋拷, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人厅缺。 一個(gè)月前我還...
    沈念sama閱讀 46,333評(píng)論 2 360
  • 正文 我出身青樓蔬顾,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親湘捎。 傳聞我的和親對(duì)象是個(gè)殘疾皇子诀豁,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,499評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容