ConstraintLayout使用指南

背景

ConstraintLayout是Google在2016年I/O大會上提出的一種全新的佈局容器,其目標是簡化佈局層次,讓佈局儘量扁平化。android

優點

它具備LinearLayout和RelativeLayotu的全部特色,如線性佈局,權重,相對位置,因此使用一層結構也可實現複雜的佈局,大大簡化了佈局的層次結構。app

位置

ConstraintLayout提供了完善的約束方式,經過合理使用,咱們可快速實現View的位置佈局:ide

app:layout_constraintTop_toBottomOf
app:layout_constraintLeft_toRightOf
app:layout_constraintRight_toLeftOf
app:layout_constraintBottom_toTopOf
app:layout_constraintStart_toEndOf
app:layout_constraintEnd_toStartOf
app:layout_constraintBaseline_toBaselineOf
複製代碼

這些屬性都是layout_constraintX_toYOf形式,看起來很複雜,其實這只是爲了清晰地表達約束條件而已,實際上在使用上咱們只須要關注toYof部分,如:toBottomof表示在指定元素的底部。佈局

既然有依賴關係,那就存在所依賴的View被隱藏的狀況,與RelativeLayout不一樣的是,若是所依賴的View被隱藏(visibility被設置爲GONE)時,它的依賴關係依然存在,同時還提供了當所依賴的View被隱藏後設置margin的功能(至關於View被隱藏了,但原來的位置提供了一個隱形的瞄點)。spa

app:layout_goneMarginTop
app:layout_goneMarginLeft
app:layout_goneMarginRight
app:layout_goneMarginBottom
複製代碼

須要注意如下幾點:code

  • 上面的這幾種屬性的值大多數狀況都應該使用指定View的id,而不是parent, 使用parent時,當前View被放置在parent的外側,因此,只有特殊狀況下才使用parent;
  • layout_goneMarginX屬性只有所依賴的一側纔有效。例如,當前View在所依賴的View的底部,那麼只有layout_goneMarginTop纔有效;
  • layout_constraintBaseline_toBaselineOf這個屬性,它表示以baseline對齊(baseline簡單來講,就是文字的底部,而不是View的底部),在文本對齊中很好用,使用RelativeLayout 時,對兩個文字大小不一樣的TextView進行底部對齊時,設置了底部對齊,還須要設置margin來手動調整,而在ConstraintLayout中,使用layout_constraintBaseline_toBaselineOf就可直接對齊。 這個屬性的優先級比layout_constraintTop_toBottomOf和layout_constraintBottom_toTopOf要高,因此同時使用時,會覆蓋上面兩個屬性的值。

邊距

在ConstraintLayout中,咱們發現layout_marginXXX不起做用,緣由是沒有對元素添加約束,因此在設置邊距時,咱們須要先設置約束條件,再使用layout_marginXXX屬性:cdn

// 距離父佈局左側24dp
android:layout_marginLeft="24dp"
app:layout_constraintLeft_toLeftOf="parent"

 // 距離id爲start_text的View左側24dp
android:layout_marginLeft="24dp"
app:layout_constraintLeft_toLeftOf="@id/start_text"
複製代碼

對齊方式

在ConstraintLayout中,子元素不能使用layout_gravity屬性設置對齊方式,而只能使用下面幾個屬性:xml

// 頂部對齊
app:layout_constraintTop_toTopOf="parent"
// 左邊對齊
app:layout_constraintLeft_toLeftOf="parent"
// 右邊對齊
app:layout_constraintRight_toRightOf="parent"
// 底部對齊
app:layout_constraintBottom_toBottomOf="parent"
複製代碼

這幾個元素的值可爲指定元素的id或parent, 爲元素id表示與指定元素對齊,設置爲parent表示與父佈局的對齊方式。雖沒有提供居中對齊(水平居中,垂直居中,居中),但可經過組合的方式來實現:blog

// 水平居中
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"

// 垂直居中
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"

// 居中
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
複製代碼

實現起來仍是比較麻煩,尤爲是居中,須要四個屬性組合才能夠實現,希望Google可以添加相應的屬性,簡化屬性實現過程。固然,也可本身擴展。seo

雖然ConstraintLayout沒有提供單個的居中屬性,但卻提供了一個很別緻的屬性——Bias, 表示居中狀況下的偏移,其取值爲[0, 1],默認爲0.5。以水平方面來講,0表示左對齊,0.5表示水平對齊,1表示右對齊。固然,前提是要設置水平居中。

// 左對齊
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintHorizontal_bias="0"

// 右對齊
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintHorizontal_bias="1"

// 從水平中心點向左偏移必定的距離,偏移的距離=(ConstraintLayout.width - View.width) * 0.25
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintHorizontal_bias="0.25"
複製代碼

==特別說明:==

ConstraintLayout中的View容許寬度或高度被設置爲0dp, 但不能同時被設置爲0dp。若是爲0dp,則以wrap_content的形式顯示。 當View居中(相對於ConstraintLayout居中或相對於指定View居中)顯示時,若是是水平居中,width被設置爲0dp,則width會被自動設置爲所依賴的View的寬度,高度同理。

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

    <TextView
        android:id="@+id/text1"
        android:layout_width="100dp"
        android:layout_height="wrap_content"
        android:text="Hello"
        android:gravity="center"/>

    <TextView
        android:id="@+id/text2"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="world"
        android:gravity="center"
        app:layout_constraintTop_toBottomOf="@id/text1"
        app:layout_constraintLeft_toLeftOf="@id/text1"
        app:layout_constraintRight_toRightOf="@id/text1"/>
</android.support.constraint.ConstraintLayout>
複製代碼

這個佈局中,text2的寬度將被自動設置成100dp。若是設置爲以父佈局居中,則寬度就是ConstraintLayout的寬度減去padding的距離。

比例

ConstraintLayout還支持比例設置,經過layout_constraintDimensionRatio便可設置View的寬高比例:

但使用時須要注意如下幾點:

  • width或height有且只有一邊須要設置爲0dp, 另外一邊須要設置爲固定值或match_parent;

  • 至少須要一個約束條件,如位置或對齊方式,不然設置的比例無效;

  • layout_constraintDimensionRatio的值表示width:height,可設置爲比例的形式,也可設置爲比例值,如2:1或2。固然,也可指定爲height:width:

    app:layout_constraintDimensionRatio="H,2:1" // 表示height:width=2:1

鏈條

Chains是ConstraintLayout又一獨特的地方,它能夠看作是LinearLayout的另類實現。不過它只是一種邏輯上存在的概念,它的構成很簡單:相互引用自成鏈。如:ViewA的位置設置爲ViewB的左側,ViewB的位置設置爲ViewA的右側,那麼它們就造成了一條鏈,這條鏈最左側或頂部的一個元素被稱爲鏈頭,在鏈頭中可經過layout_constraintHorizontal_chainStyle或layout_constraintVertical_chainStyle屬性設置Chain的樣式,它支持的樣式包括如下幾種:

spread:Views被等間距存放(默認樣式);
spread_inside: 第一個和最後一個View靠邊顯示,其餘View等間距顯示;
packed: Views緊挨着並居中顯示;
複製代碼

具體的顯示效果可參考下圖(圖片來自張旭童同窗的blog

image

使用Chain時注意一下幾點:

  • 第一個元素須要設置爲左對齊或頂部對齊,最後一個元素須要設置爲右對齊或底部對齊,不然即使互相引用,也不會以Chain形式展現。
  • 鏈頭元素不能做爲Chain外其餘View的依賴元素,不然沒法實現須要的位置關係。如ViewA須要在一條Chain的下面,則不能設置layout_constraintTop_toBottomOf爲第一個元素,不然不會產生預期的效果;

前面說了,ConstraintLayout也支持權重,只須要經過layout_constraintHorizontal_weight或layout_constraintVertical_weight來實現,如:

<Button
    android:id="@+id/button"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Button"
    app:layout_constraintEnd_toStartOf="@+id/button2"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toBottomOf="@id/container_layout"
    app:layout_constraintHorizontal_chainStyle="packed"/>

<Button
    android:id="@+id/button2"
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    android:text="Button"
    app:layout_constraintHorizontal_weight="1"
    app:layout_constraintEnd_toStartOf="@+id/button3"
    app:layout_constraintStart_toEndOf="@+id/button"/>

<Button
    android:id="@+id/button3"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Button"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toEndOf="@+id/button2"/>
複製代碼

這條Chain中button2將佔除了button1和button3以外全部空間,須要注意的是,設置權重時,對應的width或height必須設置爲0dp, 不然設置的權重無效。

示例

上面已經對的屬性進行了介紹,有必要小試牛刀了,實現如下佈局:

image

使用LinearLayout和RelativeLayout,最少也須要2層佈局才能實現,可是使用ConstraintLayout一層就可實現。

<?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"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingLeft="16dp"
    android:paddingRight="16dp">

    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="button1"
        app:layout_constraintHorizontal_chainStyle="spread"
        app:layout_constraintRight_toLeftOf="@id/button2"
        app:layout_constraintLeft_toLeftOf="parent"/>

    <Button
        android:id="@+id/button2"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="button2"
        app:layout_constraintHorizontal_weight="1"
        app:layout_constraintLeft_toRightOf="@id/button1"
        app:layout_constraintRight_toLeftOf="@id/button3"/>

    <Button
        android:id="@+id/button3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="button3"
        app:layout_constraintLeft_toRightOf="@id/button2"
        app:layout_constraintRight_toRightOf="parent"/>
    <View
        android:id="@+id/view4"
        android:layout_width="120dp"
        android:layout_height="0dp"
        android:layout_marginTop="18dp"
        android:background="#e0e0e0"
        app:layout_constraintTop_toBottomOf="@id/button2"
        app:layout_constraintDimensionRatio="3:4"/>
    <TextView
        android:id="@+id/view5"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="12dp"
        android:text="上海市"
        app:layout_constraintLeft_toRightOf="@id/view4"
        app:layout_constraintTop_toTopOf="@id/view4"/>
    <TextView
        android:id="@+id/view6"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="6dp"
        android:layout_marginLeft="12dp"
        android:text="上海市浦東新區上海市浦東新區上海市浦東新區上海市浦東新區上海市浦東新區"
        app:layout_constraintTop_toBottomOf="@id/view5"
        app:layout_constraintLeft_toRightOf="@id/view4"/>
    <TextView
        android:id="@+id/view7"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="12dp"
        android:text="上海市浦東新區"
        app:layout_constraintLeft_toRightOf="@id/view4"
        app:layout_constraintBottom_toBottomOf="@id/view4"/>
</android.support.constraint.ConstraintLayout>
複製代碼

總結

雖然ConstraintLayout很強大,但經過真實的應用,感受仍是有點複雜(須要設置的屬性太多),因此在編寫佈局時,仍是應該優先考慮RelativeLayout,對於複雜的佈局,可考慮使用ConstraintLayout。

參考連接

ConstraintLayout 屬性詳解 和Chain的使用

ConstraintLayout官方文檔

相關文章
相關標籤/搜索