帶你瞭解Android約束佈局ConstraintLayout
ConstraintLayout
是Android新推出的一個佈局,其效能更好,連官方的hello world
都用ConstraintLayout
來寫了。所以極力推薦使用ConstraintLayout
來編寫佈局。
本文主要介紹一下如何使用程式碼來編寫ConstraintLayout
佈局。
如果對ConstraintLayout
的效能比較感興趣,可以看這篇文章:解析ConstraintLayout的效能優勢
好了,開始我們的征程。
1 ConstraintLayout簡介
ConstraintLayout
,可以翻譯為約束佈局,在2016年Google I/O 大會上釋出。我們知道,當佈局巢狀過多時會出現一些效能問題。之前我們可以去通過RelativeLayout
GridLayout
來減少這種佈局巢狀的問題。現在,我們可以改用ConstraintLayout
來減少佈局的層級結構。ConstraintLayout
相比RelativeLayout
,其效能更好,也更容易使用,結合Android Studio
的佈局編輯器可以實現拖拽控制元件來編寫佈局等等。
2 引入ConstraintLayout
如果我們是新建工程,則Android Studio
會預設幫我們加入ConstraintLayout
的依賴了。
如果我們是改造舊專案,可以在build.gradle
中新增以下依賴:
implementation 'com.android.support.constraint:constraint-layout:1.1.2'
然後就可以使用ConstraintLayout
了。
3 相對位置
要在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>
顯示效果如下:
4 尺寸約束
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>
其效果如下:
5 寬高比
在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的比例設定高度。
6 百分比寬高
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>
效果如下:
7 位置偏向
如果想讓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>
顯示效果如下:
8 權重
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"