注:本文是玉剛說的副本
ConstraintLayout
是Android新推出的一個布局,其性能更好,連官方的hello world
都用ConstraintLayout
來寫了。所以極力推薦使用ConstraintLayout
來編寫布局。
本文主要介紹一下如何使用代碼來編寫ConstraintLayout
布局。
好了,開始我們的征程。
ConstraintLayout簡介
ConstraintLayout
,可以翻譯為約束布局,在2016年Google I/O 大會上發布。我們知道,當布局嵌套過多時會出現一些性能問題。之前我們可以去通過RelativeLayout
或者GridLayout
來減少這種布局嵌套的問題。現在,我們可以改用ConstraintLayout
來減少布局的層級結構。ConstraintLayout
相比RelativeLayout
,其性能更好,也更容易使用,結合Android Studio
的布局編輯器可以實現拖拽控件來編寫布局等等。
如果我們是新建工程,則Android Studio
會默認幫我們加入ConstraintLayout
的依賴了。如果我們是改造舊項目,可以在build.gradle
中添加以下依賴:
implementation 'com.android.support.constraint:constraint-layout:1.1.2'
然后就可以使用ConstraintLayout
了。
相對位置
要在ConstraintLayout
中確定view
的位置,必須至少添加一個水平和垂直的約束。每一個約束表示到另一個view
,父布局,或者不可見的參考線的連接或者對齊。如果水平或者垂直方向上沒有約束,那么其位置就是0。
我們先來看個例子:
<?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">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="左對齊"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="右對齊"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="水平居中"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="垂直居中"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="底部對齊"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="水平居中+垂直居中"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
</android.support.constraint.ConstraintLayout>
其顯示效果如下圖所示:
上面例子中app:layout_constraintLeft_toLeftOf="parent"
表示view
的左邊對齊父布局的左邊。
app:layout_constraintRight_toRightOf="parent"
則表示view
的右邊對齊父布局的右邊。
其他同理,就不一一說明。
相對位置的屬性
下面是ConstraintLayout
確定位置的屬性:
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
這些屬性的值即可以是parent
,也可以是某個view的id
。
居中顯示
如果一個view
滿足以下
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
即view的左邊對齊父布局的左邊,view的右邊對齊父布局的右邊,除非這個view的大小剛好充滿整個父布局;否則的話,就是水平居中顯示了。我們可以理解為有兩個力,它們左右互搏,view只能給扯到中間了。
再來兩個例子,把上面的屬性基本都涉及到了,看下估計就懂了,就不逐一說明了。
- 例子一:水平方向的相對位置
這里主要關注水平方式的屬性即可。
布局代碼:
<?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">
<Button
android:id="@+id/btn_center"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#00f"
android:text="水平參照物"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#f00"
android:text="Left_toLeftOf"
app:layout_constraintBottom_toTopOf="@id/btn_center"
app:layout_constraintLeft_toLeftOf="@id/btn_center"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#0f0"
android:text="Right_toLeftOf"
app:layout_constraintBottom_toTopOf="@id/btn_center"
app:layout_constraintRight_toLeftOf="@id/btn_center"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#0f0"
android:text="Right_toRightOf"
app:layout_constraintRight_toRightOf="@id/btn_center"
app:layout_constraintTop_toBottomOf="@id/btn_center"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#f00"
android:text="Left_toRightOf"
app:layout_constraintLeft_toRightOf="@id/btn_center"
app:layout_constraintTop_toBottomOf="@id/btn_center"/>
</android.support.constraint.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" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/btn_center"
android:layout_width="wrap_content"
android:layout_height="100dp"
android:background="#00f"
android:text="豎直參照物"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#f00"
android:text="Top_toTopOf"
app:layout_constraintTop_toTopOf="@id/btn_center"
app:layout_constraintRight_toLeftOf="@id/btn_center"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#0f0"
android:text="Bottom_toTopOf"
app:layout_constraintBottom_toTopOf="@id/btn_center"
app:layout_constraintRight_toLeftOf="@id/btn_center"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#0f0"
android:text="Top_toBottomOf"
app:layout_constraintLeft_toRightOf="@id/btn_center"
app:layout_constraintTop_toBottomOf="@id/btn_center"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#f00"
android:text="Bottom_toBottomOf"
app:layout_constraintLeft_toRightOf="@id/btn_center"
app:layout_constraintBottom_toBottomOf="@id/btn_center"/>
</android.support.constraint.ConstraintLayout>
顯示效果如下:
尺寸約束
view
中使用warp_content
或者固定值等等是沒有問題的。但是ConstraintLayout
中不支持MATCH_PARENT
這個值,如果需要實現跟MATCH_PARENT
同樣的效果,可以使用0dp
來代替,其表示MATCH_CONSTRAINT
,即適應約束。其跟MATCH_PARENT
還是有區別的,后面的例子(寬高比那一小節)會提到。
我們來看下例子:
<?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">
<Button
android:id="@+id/btn_center"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="wrap_content"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<Button
android:id="@+id/btn_1"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:text="具體數值:200dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/btn_center"/>
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="0dp(MATCH_CONSTRAINT)"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/btn_1"/>
</android.support.constraint.ConstraintLayout>
其效果如下:
寬高比
在ConstraintLayout
中,還可以將寬定義成高的一個比例或者高定義成寬的比率。首先,需要將寬或者高設置為0dp
(即MATCH_CONSTRAINT
),即要適應約束條件。然后通過layout_constraintDimensionRatio
屬性設置一個比率即可。這個比率可以是一個浮點數
,表示寬度和高度之間的比率;也可以是“寬度:高度
”形式的比率。比如:
<?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">
<Button
android:layout_width="wrap_content"
android:layout_height="0dp"
android:text="-------------------寬高比2:1-------------------"
app:layout_constraintDimensionRatio="2:1"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"/>
</android.support.constraint.ConstraintLayout>
這里將按鈕的高度設置為寬度的一半了。如下圖所示:
如果寬和高都設置為0dp
(MATCH_CONSTRAINT
),那么layout_constraintDimensionRatio
的值需要先加一個"W,"
或者"H,"
來表示約束寬度或高度。如下:
<Button
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintDimensionRatio="H,16:9"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
這里例子是說,首先寬度將滿足父布局的約束,然后將按照16:9的比例設置高度。
百分比寬高
ConstraintLayout
還能使用百分比來設置view的寬高。
要使用百分比,寬或高同樣要設置為0dp
(MATCH_CONSTRAINT
)。
然后設置以下屬性即可:
app:layout_constraintWidth_default="percent" //設置寬為百分比app:layout_constraintWidth_percent="0.3" //0到1之間的值或app:layout_constraintHeight_default="percent" //設置高為百分比app:layout_constraintHeight_percent="0.3" //0到1之間的值
例子如下:
<?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">
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="寬50%"
app:layout_constraintHeight_default="percent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintWidth_percent="0.5"/>
</android.support.constraint.ConstraintLayout>
效果如下:
位置偏向
如果想讓view
的位置偏向某一側,可以使用以下的兩個屬性來設置:
layout_constraintHorizontal_bias //水平偏向layout_constraintVertical_bias //豎直偏向
其值同樣也是0到1之間。
比如,以下例子為橫向偏向左側30%,默認的居中效果就是50%:
<?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">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="左邊偏向30%"
app:layout_constraintHorizontal_bias="0.3"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"/>
</android.support.constraint.ConstraintLayout>
顯示效果如下:
權重
LinearLayout
中可以設置權重,ConstraintLayout
同樣也有這玩意。
通過設置以下兩個屬性:
app:layout_constraintHorizontal_weight //水平權重
app:layout_constraintVertical_weight //豎直權重
然后將相連的view兩兩約束好即可。如下:
<?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">
<Button
android:id="@+id/btn_1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="權重為1"
app:layout_constraintHorizontal_weight="1"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@id/btn_2"/>
<Button
android:id="@+id/btn_2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="權重為2"
app:layout_constraintHorizontal_weight="2"
app:layout_constraintLeft_toRightOf="@id/btn_1"
app:layout_constraintRight_toLeftOf="@id/btn_3"/>
<Button
android:id="@+id/btn_3"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintHorizontal_weight="2"
android:text="權重為2"
app:layout_constraintLeft_toRightOf="@id/btn_2"
app:layout_constraintRight_toRightOf="parent"/>
</android.support.constraint.ConstraintLayout>
顯示效果如下:
鏈
上面這種將相連的view
兩兩約束好的實際上就形成了鏈。在ConstraintLayout
中可以實現各種不同的鏈,權重鏈是其中一種。整個鏈由鏈中的第一個view
(鏈頭)上設置的屬性控制。
官網上一共有5種樣式的鏈:
可以通過以下屬性來設置鏈的樣式:
app:layout_constraintHorizontal_chainStyle="spread|spread_inside|packed"
下面簡單說下上面5種樣式的實現:
-
Spread Chain
默認樣式就是spread
,所以可以不用設置。然后寬或高非0即可。
效果如下圖:
所以:Spread Chain = spread + 寬或高非0
-
Spread Inside Chain
這里設置以下屬性
app:layout_constraintHorizontal_chainStyle="spread_inside"
然后寬度同樣為非0,效果如下:
所以:Spread Inside Chain = spread_inside + 寬或高非0
Weighter Chain
即權重鏈,具體可以查看上一小節。
Weighter Chain = spread + 寬或高為0 + 權重值Packed Chain
Packed是一種view聚攏起來的效果,這里設置以下屬性
app:layout_constraintHorizontal_chainStyle="packed"
寬度同樣為非0,效果如下:
所以:Packed Chain = packed + 寬或高非0
-
Packed Chain with bias
就是Packed Chain再加一個偏向屬性,偏向屬性可以看下前面的內容。
效果如下圖所示:image所以:Packed Chain with bias = Packed Chain + bias
Guideline輔助線
Guideline
可以用來輔助布局,通過Guideline
能創建出一條條的水平線或者垂直線,該線不會顯示到界面上,但是能夠利用這些線條來添加約束去完成界面的布局。
Guideline主要的屬性有:
android:orientation="horizontal|vertical"
app:layout_constraintGuide_begin="30dp"
app:layout_constraintGuide_end="30dp"
app:layout_constraintGuide_percent="0.5"
android:orientation=”horizontal|vertical”表示是水平或垂直引導線。
app:layout_constraintGuide_begin=”30dp”,如果是水平引導線,則距離布局頂部30dp,如果是垂直引導線,則距離布局左邊30dp。
app:layout_constraintGuide_end=”30dp”,如果是水平引導線,則距離布局底部30dp,如果是垂直引導線,則距離布局右邊30dp。
app:layout_constraintGuide_percent=”0.5”,如果是水平引導線,則距離布局頂部為整個布局高度的50%,如果是垂直引導線,則距離布局左邊文這個布局寬度的50%。
來看個例子:
<?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.support.constraint.Guideline
android:id="@+id/guideline_h"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.5"/>
<android.support.constraint.Guideline
android:id="@+id/guideline_v"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.5"/>
<Button
app:layout_constraintLeft_toLeftOf="@id/guideline_v"
app:layout_constraintTop_toTopOf="@id/guideline_h"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="輔助線定位"/>
</android.support.constraint.ConstraintLayout>
如下圖所示:
本節基本把ConstraintLayout
的常用屬性都介紹了一遍了。通過使用ConstraintLayout
能夠減少布局嵌套等,可以有效的提升性能。