1. 程式人生 > >帶你瞭解Android約束佈局ConstraintLayout

帶你瞭解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>

其顯示效果如下圖所示: 相對位置.png

上面例子中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>

顯示效果如下: 水平方向的相對位置.png

  • 例子二:豎直方向的相對位置 這裡主要關注豎直方向的屬性即可。 佈局程式碼:
<?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>

顯示效果如下: 豎直方向的相對位置.png

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>

其效果如下: 尺寸大小.png

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>

這裡將按鈕的高度設定為寬度的一半了。如下圖所示: 寬高比1.png

如果寬和高都設定為0dpMATCH_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的寬高。 要使用百分比,寬或高同樣要設定為0dpMATCH_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>

效果如下: 百分比寬高.png

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>

顯示效果如下: 左邊偏向.png

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"