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
在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)
使用Chain時注意一下幾點:
前面說了,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, 不然設置的權重無效。
上面已經對的屬性進行了介紹,有必要小試牛刀了,實現如下佈局:
使用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。