天天看點

ConstraintLayout詳解

1.介紹

限制布局

ConstraintLayout

本身就是一個ViewGroup,它用來解決布局嵌套過多的問題(嵌套越多,繪制消耗的時間越長),以靈活的方式定位/調整小部件(API 9以上均可使用),相比RelativeLayout更靈活,性能更加的出色,更好的适配螢幕大小不同的機型。Android Studio 2.3開始預設建立Activity是都是使用它。

2.使用

使用它也非常的簡單,高版本的AS通常都會自動的添加它的依賴,如果未添加依賴在app/build.gradle中添加相應的依賴即可。

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

2.1 相對定位

即一個元件相對于另一個元件的限制,非常的好了解(與RelativeLayout非常的類似)。

例:要實作B在A的右側:

ConstraintLayout詳解

按鈕A在按鈕B的右側,也可以了解為按鈕B的左側位于按鈕A的右側;其他的方位都一樣。我們在代碼中的表示如下:

<Button
        android:id="@+id/btn1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button1" />

    <Button
        android:id="@+id/btn2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button2"
        app:layout_constraintLeft_toRightOf="@id/btn1" />
           

其中最關鍵的屬性為

app:layout_constraintLeft_toRightOf="@id/btn1"

,代表按鈕B的左側位于按鈕A的右側

其中常用的屬性還有:

// 值可以為parent,意思就是A的左側位于父布局的左側(top_top|bottom_bottom等一樣)
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
           

引用官方的一張圖來說明這些屬性:

ConstraintLayout詳解

比較特殊的有

layout_constraintBaseline_toBaselineOf

,如圖所示,兩個Button的高度不一緻,但是又希望他們文本對齊,這個時候就可以使用

layout_constraintBaseline_toBaselineOf

保證文字相對齊:

ConstraintLayout詳解
<Button
        android:id="@+id/btn3"
        android:layout_width="wrap_content"
        android:layout_height="100dp"
        android:text="Button3"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintHorizontal_bias="0.3"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/btn4"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="20dp"
        android:text="Button4"
        app:layout_constraintBaseline_toBaselineOf="@id/btn3"
        app:layout_constraintLeft_toRightOf="@id/btn3" />
           

2.2 角度定位

角度定位指的是利用角度以及距離決定某些控件中心點的坐标。

三個屬性為:

  1. app:layout_constraintCircle="@id/btn3"

    指定相對于哪個控件
  2. app:layout_constraintCircleAngle="160"

    角度
  3. app:layout_constraintCircleRadius="150dp"

    中心點的距離

其中的關系如下圖所示:

ConstraintLayout詳解

例子:按鈕5在按鈕3的160度方向距離為150dp

<Button
        android:id="@+id/btn3"
        android:layout_width="wrap_content"
        android:layout_height="100dp"
        android:text="Button3"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintHorizontal_bias="0.3"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
 <Button
        android:id="@+id/btn5"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button5"
        app:layout_constraintCircle="@id/btn3"
        app:layout_constraintCircleAngle="160"
        app:layout_constraintCircleRadius="150dp" />
           

效果圖:

ConstraintLayout詳解

2.3 Margin

使用Margin時,用法與其他布局的一緻,前提條件是:必須指定了相對應的限制,Margin值隻能大于等于0。

唯一特殊的地方:在對應限制的控件隐藏時,相當于一個點,可使用如下Margin來設定隐藏後的Margin值

layout_goneMarginStart
layout_goneMarginEnd
layout_goneMarginLeft
layout_goneMarginTop
layout_goneMarginRight
layout_goneMarginBottom
           

2.4 居中偏移

如何實作居中:即利用相對定位中的4個屬性即可

app:layout_constraintBottom_toBottomOf="parent"
 app:layout_constraintLeft_toLeftOf="parent"
 app:layout_constraintRight_toRightOf="parent"
 app:layout_constraintTop_toTopOf="parent"
           

偏移(Bias): 使用

app:layout_constraintHorizontal_bias="0.3"

屬性即可(值在0-1之間)

1.

layout_constraintHorizontal_bias 水準偏移

2.

layout_constraintVertical_bias 垂直偏移

上下居中,水準偏移為0.3

ConstraintLayout詳解

2.5 尺寸限制

提供了一下四種方式:

  1. 固定值
  2. wrap_content,自己進行計算

    當控件的高度或寬度為wrap_content時,可以使用下列屬性來控制最大、最小的高度或寬度:

    android:minWidth 最小的寬度

    android:minHeight 最小的高度

    android:maxWidth 最大的寬度

    android:maxHeight 最大的高度

  3. 使用0dp 官方不推薦在ConstraintLayout中使用match_parent,可設定

    0dp(MATCH_CONSTRAINT)配合代替match_parent

    寬高比:當寬或高至少一個被設定為0dp時,可通過屬性layout_constraintDimensionRatio設定寬高比還可以在值的前面加上W或者H

    app:layout_constraintDimensionRatio="W,2:1" 寬高比2:1

    app:layout_constraintDimensionRatio="H,2:1" 高寬比2:1

<Button
        android:id="@+id/btn6"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="Button6"
        android:layout_marginStart="20dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@id/btn5" />

 <!-- 通過layout_constraintDimensionRatio 設定寬高比 -->
    <Button
        android:id="@+id/btn7"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="Button7"
        app:layout_constraintDimensionRatio="W,2:1"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@id/btn6" />
           

效果圖:

ConstraintLayout詳解

2.6 鍊

如果兩個或以上控件通過下圖的方式限制在一起,就可以認為是他們是一條鍊(圖為橫向的鍊,縱向同理)。

ConstraintLayout詳解

一條鍊的第一個控件是這條鍊的鍊頭,我們可以在鍊頭中設定鍊的Style,相關的Style有:

app:layout_constraintHorizontal_chainStyle="spread|spread_inside|packed"

app:layout_constraintVertical_chainStyle="spread|spread_inside|packed"

  1. CHAIN_SPREAD : 預設模式(展開元素)
  2. CHAIN_SPREAD_INSIDE :展開元素,兩端靠近parent邊緣
  3. CHAIN_PACKED :控件被整合在一起
  4. Weighted Chain: 權重鍊,當寬度或者高度被設定成0dp時,layout_constraintHorizontal_weight 和 layout_constraintVertical_weight控制所占比例

注意:在鍊中的元素上使用邊距時,邊距是相加的。A Margin right 10,B Margin left 5,total 15

Style的形式使用下圖表示:

ConstraintLayout詳解

使用案例:

<Button
        android:id="@+id/btn1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button1"
        app:layout_constraintHorizontal_chainStyle="packed"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toLeftOf="@id/btn2" />

    <Button
        android:id="@+id/btn2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button2"
        app:layout_constraintLeft_toRightOf="@id/btn1"
        app:layout_constraintRight_toLeftOf="@id/btn3" />

    <Button
        android:id="@+id/btn3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button3"
        app:layout_constraintLeft_toRightOf="@id/btn2"
        app:layout_constraintRight_toRightOf="parent" />
           

packed模式:

ConstraintLayout詳解

spread模式:

ConstraintLayout詳解

spread_inside模式:

ConstraintLayout詳解

Weighted Chain模式,必須存在一個0dp:

ConstraintLayout詳解

3.輔助工具的使用

3.1 Optimizer

當我們使用 MATCH_CONSTRAINT 時,ConstraintLayout 将對控件進行 2 次測量,ConstraintLayout在1.1中可以通過設定 layout_optimizationLevel 進行優化,可設定的值有:

  1. none 無優化
  2. Standard 僅優化直接限制/屏障限制(預設)
  3. Direct 優化直接限制
  4. Barrier 優化屏障限制
  5. Chain 優化鍊限制
  6. Dimensions 優化尺寸測量

3.2 Barrier(屏障)

詳參:https://developer.android.google.cn/reference/android/support/constraint/Barrier

A與B的寬度未知,現在讓C限制在A或者B的右側都不對;這種情況可用Barrier解決,它相當于在AB的一側與C之間加了一個屏障。

ConstraintLayout詳解

使用Barrier後如下圖(A B都在屏障内):

ConstraintLayout詳解

主要的屬性:

app:barrierDirection="end|top|bottom|start|left|right"

等設定屏障的位置

app:constraint_referenced_ids=””

設定屏障引用的控件,多個值時用’,’隔開

例子:

<?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:ignore="MissingConstraints">

    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="15dp"
        android:layout_marginTop="15dp"
        android:text="Button4"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/button2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="15dp"
        android:layout_marginTop="6dp"
        android:text="Button5 Button5"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/button1" />

    <android.support.constraint.Barrier
        android:id="@+id/barrier"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:barrierDirection="end"
        app:constraint_referenced_ids="button1,button2" />

    <TextView
        android:id="@+id/textView3"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginTop="16dp"
        android:layout_marginEnd="10dp"
        android:text="為了看到整體的效果,可以切換語言,
        此時你會看到Barrier會自動位于較寬的那個textView後面,
        也就間接讓 textView3 也位于了正确的位置"
        app:layout_constraintLeft_toRightOf="@id/barrier"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</android.support.constraint.ConstraintLayout>
           

效果:

ConstraintLayout詳解

最終在C中引用Barrier的限制即可,使用後不管A或者B的寬度如何變化,C始終都位于屏障的右側

3.3 Group

詳參:https://developer.android.google.cn/reference/android/support/constraint/Group

主要作用:把控件歸類為一組,更加便捷的管理顯示與否等

控件隐藏前:

ConstraintLayout詳解

使用Group,并且添加相關的依賴:

app:constraint_referenced_ids="btn2,btn3"關聯關系

<?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:context=".MainActivity"
    tools:ignore="MissingConstraints">

    <Button
        android:id="@+id/btn1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button1" />

    <Button
        android:id="@+id/btn2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button2"
        app:layout_constraintLeft_toRightOf="@id/btn1" />

    <Button
        android:id="@+id/btn3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button3"
        app:layout_constraintLeft_toRightOf="@id/btn2" />

    <android.support.constraint.Group
        app:constraint_referenced_ids="btn2,btn3"
        android:visibility="visible"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</android.support.constraint.ConstraintLayout>
           

控件隐藏後:

ConstraintLayout詳解

3.4 Placeholder

詳參:https://developer.android.google.cn/reference/android/support/constraint/Placeholder

占位符,可使用setContent設定另一個控件的id,使這個控件移動到占位符的位置.

通過

app:content="@+id/btn1"

屬性設定要移動的View

案例:設定Button在右上角,設定Placeholder在左下角,設定content後,Button移動到Placeholder的位置(左下角)

<?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:context=".MainActivity"
    tools:ignore="MissingConstraints">

    <Button
        android:id="@+id/btn1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button1"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <android.support.constraint.Placeholder
        android:id="@+id/ph"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:content="@+id/btn1"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent" />


</android.support.constraint.ConstraintLayout>
           

效果:

ConstraintLayout詳解
ConstraintLayout詳解

3.5 Guideline

詳參:https://developer.android.google.cn/reference/android/support/constraint/Guideline

布局輔助線,預覽的時候幫助我們完成布局(不顯示在界面上)

主要屬性:

android:orientation="horizontal|vertical"

app:layout_constraintGuide_end = “50dp”

結束位置

app:layout_constraintGuide_begin = “50dp”

開始位置

app:layout_constraintGuide_percent="0.6"

距離頂部的百分比(orientation = horizontal時則為距離左邊)

例子:

<?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:context=".MainActivity"
    tools:ignore="MissingConstraints">

    <Button
        android:id="@+id/btn1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button1" />

    <android.support.constraint.Guideline
        android:id="@+id/line1"
        android:orientation="horizontal"
        app:layout_constraintGuide_begin="50dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <android.support.constraint.Guideline
        android:id="@+id/line2"
        android:orientation="vertical"
        app:layout_constraintGuide_percent="0.6"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <android.support.constraint.Guideline
        android:id="@+id/line3"
        android:orientation="horizontal"
        app:layout_constraintGuide_end="50dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</android.support.constraint.ConstraintLayout>
           

效果:

ConstraintLayout詳解

ConstraintLayout 的使用就簡單介紹到這裡

參考文章