1. 程式人生 > 其它 >Android入門教程 | 使用 ConstraintLayout 構建自適應介面

Android入門教程 | 使用 ConstraintLayout 構建自適應介面

ConstraintLayout 可使用扁平檢視層次結構(無巢狀檢視組)建立複雜的大型佈局。它與 RelativeLayout 相似,其中所有的檢視均根據同級檢視與父佈局之間的關係進行佈局,但其靈活性要高於 RelativeLayout,並且更易於與 Android Studio 的佈局編輯器配合使用。

約束條件

建立約束條件時,請注意以下規則:

  • 每個檢視都必須至少有兩個約束條件:一個水平約束條件,一個垂直約束條件。
  • 只能在共用同一平面的約束手柄與定位點之間建立約束條件。因此,檢視的垂直平面(左側和右側)只能約束在另一個垂直平面上;而基準線則只能約束到其他基準線上。
  • 每個約束控制代碼只能用於一個約束條件,但您可以在同一定位點上建立多個約束條件(從不同的檢視)。

gradle 引入

引入 constraintlayout 庫

implementation 'androidx.constraintlayout:constraintlayout:1.1.3'

constraintlayout 使用

在 layout 中使用android.support.constraint.ConstraintLayout,如下示例

<androidx.constraintlayout.widget.ConstraintLayout
 android:layout_width="match_parent"
 android:layout_height="50dp"
 app:layout_constraintTop_toTopOf="parent">
​
 <!-- child view layout -->
​
 </androidx.constraintlayout.widget.ConstraintLayout>

style中新建一個樣式,方便後面操作

<!-- con layout 示例text -->
 <style name="ConSampleText">
 <item name="android:layout_width">wrap_content</item>
 <item name="android:layout_height">wrap_content</item>
 <item name="android:padding">4dp</item>
 <item name="android:textColor">#fff</item>
 <item name="android:background">#3F51B5</item>
 </style>

若子 view 沒有新增約束,則會跑到父 constraintlayout 的(0,0)位置

<androidx.constraintlayout.widget.ConstraintLayout
 android:id="@+id/c1"
 android:layout_width="match_parent"
 android:layout_height="50dp"
 android:background="#f0f0f0"
 app:layout_constraintTop_toTopOf="parent">
​
 <TextView
 style="@style/ConSampleText"
 android:text="No rule, jump to (0,0)" />
​
 </androidx.constraintlayout.widget.ConstraintLayout>
對齊,屬性說明

定位時使用到諸如app:layout_constraintStart_toStartOf或者app:layout_constraintTop_toTopOf屬性。

app:layout_constraintStart_toStartOf,裡面有2個Start字眼。 第一個Start表示自身的起始位置(預設是左邊)。第二個toStartOf表示對齊參照物的起始位置。

app:layout_constraintTop_toTopOf也類似。與參照物頂部對齊。

指定位置的字眼,如TopBottomEndStart,它們組合使用可用來確定相對位置:app:layout_constraint{}_to{}Of

相對父 layout 的定位

將子 view 對齊到父 layout 的各個邊緣位置。

約束的參考物件是parent

<androidx.constraintlayout.widget.ConstraintLayout
 android:id="@+id/c2"
 android:layout_width="match_parent"
 android:layout_height="140dp"
 android:layout_marginTop="20dp"
 android:background="#f0f0f0"
 app:layout_constraintTop_toBottomOf="@id/c1">
​
 <!-- 相對父layout的邊緣定位 -->
​
 <TextView
 style="@style/ConSampleText"
 android:text="居中"
 app:layout_constraintBottom_toBottomOf="parent"
 app:layout_constraintEnd_toEndOf="parent"
 app:layout_constraintStart_toStartOf="parent"
 app:layout_constraintTop_toTopOf="parent" />
​
 <TextView
 style="@style/ConSampleText"
 android:text="左上角"
 app:layout_constraintStart_toStartOf="parent"
 app:layout_constraintTop_toTopOf="parent" />
​
 <TextView
 style="@style/ConSampleText"
 android:text="左下角"
 app:layout_constraintBottom_toBottomOf="parent"
 app:layout_constraintStart_toStartOf="parent" />
​
 <TextView
 style="@style/ConSampleText"
 android:text="右下角"
 app:layout_constraintBottom_toBottomOf="parent"
 app:layout_constraintEnd_toEndOf="parent" />
​
 <TextView
 style="@style/ConSampleText"
 android:text="右上角"
 app:layout_constraintEnd_toEndOf="parent"
 app:layout_constraintTop_toTopOf="parent" />
​
 <TextView
 style="@style/ConSampleText"
 android:text="頂部水平居中"
 app:layout_constraintEnd_toEndOf="parent"
 app:layout_constraintStart_toStartOf="parent"
 app:layout_constraintTop_toTopOf="parent" />
​
 <TextView
 style="@style/ConSampleText"
 android:text="底部水平居中"
 app:layout_constraintBottom_toBottomOf="parent"
 app:layout_constraintEnd_toEndOf="parent"
 app:layout_constraintStart_toStartOf="parent" />
​
 <TextView
 style="@style/ConSampleText"
 android:text="左邊垂直居中"
 app:layout_constraintBottom_toBottomOf="parent"
 app:layout_constraintStart_toStartOf="parent"
 app:layout_constraintTop_toTopOf="parent" />
​
 <TextView
 style="@style/ConSampleText"
 android:text="右邊垂直居中"
 app:layout_constraintBottom_toBottomOf="parent"
 app:layout_constraintEnd_toEndOf="parent"
 app:layout_constraintTop_toTopOf="parent" />
​
 </androidx.constraintlayout.widget.ConstraintLayout>
基線對齊

將一個檢視的文字基線與另一檢視的文字基線對齊。

可以使用app:layout_constraintBaseline_toBaselineOf屬性設定基線對齊。

示例

<androidx.constraintlayout.widget.ConstraintLayout
 android:id="@+id/c21"
 android:layout_width="match_parent"
 android:layout_height="100dp"
 android:background="#f0f0f0"
 app:layout_constraintTop_toTopOf="parent">
​
 <TextView
 android:id="@+id/tv1"
 style="@style/ConSampleText"
 android:layout_marginStart="10dp"
 android:text=""
 android:textSize="13sp"
 app:layout_constraintBottom_toBottomOf="parent"
 app:layout_constraintStart_toStartOf="parent"
 app:layout_constraintTop_toTopOf="parent" />
​
 <TextView
 android:id="@+id/tv2"
 style="@style/ConSampleText"
 android:layout_marginStart="10dp"
 android:text=""
 android:textSize="20sp"
 app:layout_constraintBaseline_toBaselineOf="@id/tv1"
 app:layout_constraintStart_toEndOf="@+id/tv1" />
​
 <TextView
 android:id="@+id/tv3"
 style="@style/ConSampleText"
 android:layout_marginStart="10dp"
 android:text=""
 android:textSize="24sp"
 app:layout_constraintBaseline_toBaselineOf="@id/tv1"
 app:layout_constraintStart_toEndOf="@+id/tv2" />
​
 </androidx.constraintlayout.widget.ConstraintLayout>
引導線約束 Guideline

在 ConstraintLayout 中新增引導線,可以方便定位。其他 View 可以引導線作為參考位置。

新增 Guideline,需要確定它的方向,分別是垂直和水平。 - android:orientation="vertical" - android:orientation="horizontal"

比例定位

這裡按比例來定位,使用app:layout_constraintGuide_percent。 需要指定比例值,例如app:layout_constraintGuide_percent="0.5"

<androidx.constraintlayout.widget.ConstraintLayout
 android:id="@+id/c3"
 android:layout_width="match_parent"
 android:layout_height="240dp"
 android:layout_marginTop="40dp"
 android:background="#f0f0f0"
 app:layout_constraintTop_toBottomOf="@id/c2">
​
 <!-- 引導線約束: 相對父layout 按比例定位 -->
​
 <!-- 垂直引導線 Guideline -->
 <androidx.constraintlayout.widget.Guideline
 android:id="@+id/g1"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:orientation="vertical"
 app:layout_constraintGuide_percent="0.33" />
​
 <androidx.constraintlayout.widget.Guideline
 android:id="@+id/g2"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:orientation="horizontal"
 app:layout_constraintGuide_percent="0.5" />
​
 <TextView
 android:id="@+id/t1"
 style="@style/ConSampleText"
 android:text="垂直的1/3引導線後"
 app:layout_constraintStart_toStartOf="@id/g1"
 app:layout_constraintTop_toTopOf="parent" />
​
 <TextView
 android:id="@+id/t2"
 style="@style/ConSampleText"
 android:text="垂直的1/3引導線前"
 app:layout_constraintEnd_toStartOf="@id/g1"
 app:layout_constraintTop_toTopOf="parent" />
​
 <TextView
 android:id="@+id/t3"
 style="@style/ConSampleText"
 android:layout_marginTop="2dp"
 android:text="垂直的1/3引導線居中"
 app:layout_constraintEnd_toEndOf="@id/g1"
 app:layout_constraintStart_toStartOf="@id/g1"
 app:layout_constraintTop_toBottomOf="@id/t2" />
​
 <TextView
 android:id="@+id/th1"
 style="@style/ConSampleText"
 android:text="水平的1/2引導線居中"
 app:layout_constraintBottom_toBottomOf="@id/g2"
 app:layout_constraintStart_toStartOf="parent"
 app:layout_constraintTop_toTopOf="@id/g2" />
​
 <TextView
 android:id="@+id/th2"
 style="@style/ConSampleText"
 android:layout_marginStart="2dp"
 android:text="水平的1/2引導線上面"
 app:layout_constraintBottom_toBottomOf="@id/g2"
 app:layout_constraintStart_toEndOf="@id/th1" />
​
 <TextView
 android:id="@+id/th3"
 style="@style/ConSampleText"
 android:layout_marginStart="2dp"
 android:text="水平的1/2引導線下面"
 app:layout_constraintStart_toEndOf="@id/th1"
 app:layout_constraintTop_toBottomOf="@id/g2" />
​
 <androidx.constraintlayout.widget.Guideline
 android:id="@+id/gv75"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:orientation="vertical"
 app:layout_constraintGuide_percent="0.75" />
​
 <androidx.constraintlayout.widget.Guideline
 android:id="@+id/gh75"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:orientation="horizontal"
 app:layout_constraintGuide_percent="0.75" />
​
 <TextView
 style="@style/ConSampleText"
 android:layout_marginStart="2dp"
 android:text="(0.75,0.75)"
 app:layout_constraintBottom_toBottomOf="@id/gh75"
 app:layout_constraintEnd_toEndOf="@id/gv75"
 app:layout_constraintStart_toStartOf="@id/gv75"
 app:layout_constraintTop_toTopOf="@id/gh75" />
​
 <TextView
 style="@style/ConSampleText"
 android:layout_marginStart="2dp"
 android:text="(0.33, 0.75)"
 app:layout_constraintBottom_toBottomOf="@id/gh75"
 app:layout_constraintEnd_toEndOf="@id/g1"
 app:layout_constraintStart_toStartOf="@id/g1"
 app:layout_constraintTop_toTopOf="@id/gh75" />
​
 </androidx.constraintlayout.widget.ConstraintLayout>

具體數值

我們也可以使用app:layout_constraintGuide_end或者app:layout_constraintGuide_begin來指定具體的數值。

<androidx.constraintlayout.widget.ConstraintLayout
 android:id="@+id/c4"
 android:layout_width="match_parent"
 android:layout_height="50dp"
 android:layout_marginTop="30dp"
 android:background="#f0f0f0"
 app:layout_constraintTop_toBottomOf="@id/c3">
​
 <androidx.constraintlayout.widget.Guideline
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:orientation="horizontal"
 app:layout_constraintGuide_begin="10dp" />
​
 <androidx.constraintlayout.widget.Guideline
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:orientation="horizontal"
 app:layout_constraintGuide_end="10dp" />
​
 <androidx.constraintlayout.widget.Guideline
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:orientation="vertical"
 app:layout_constraintGuide_begin="10dp" />
​
 <androidx.constraintlayout.widget.Guideline
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:orientation="vertical"
 app:layout_constraintGuide_end="10dp" />
​
 </androidx.constraintlayout.widget.ConstraintLayout>
屏障約束

與引導線類似,屏障是一條隱藏的線,可以用它來約束檢視。屏障不會定義自己的位置;相反,屏障的位置會隨著其中所含檢視的位置而移動。 如果希望將檢視限制到一組檢視而不是某個特定檢視,這就非常有用。

豎直屏障示例

這是一個豎直屏障的例子。barrier1以tv221和tv222作為參考。

設定app:barrierDirection="end",並且設定tv223在它的右側。

也就是barrier1會被tv221和tv222“推”著走。

<androidx.constraintlayout.widget.ConstraintLayout
 android:id="@+id/c22"
 android:layout_width="match_parent"
 android:layout_height="120dp"
 android:layout_marginTop="10dp"
 android:background="#f3f3f3"
 app:layout_constraintEnd_toEndOf="parent"
 app:layout_constraintStart_toStartOf="parent"
 app:layout_constraintTop_toBottomOf="@id/c21">
​
 <TextView
 android:id="@+id/tv221"
 style="@style/ConSampleText"
 android:layout_marginStart="10dp"
 android:text="an"
 app:layout_constraintStart_toStartOf="parent"
 app:layout_constraintTop_toTopOf="parent" />
​
 <TextView
 android:id="@+id/tv222"
 style="@style/ConSampleText"
 android:layout_marginTop="4dp"
 android:text="RustFisher"
 app:layout_constraintStart_toStartOf="parent"
 app:layout_constraintTop_toBottomOf="@id/tv221" />
​
 <TextView
 style="@style/ConSampleText"
 android:layout_marginTop="4dp"
 android:text="沒有以此作為參考,不管這個有多長"
 app:layout_constraintStart_toStartOf="parent"
 app:layout_constraintTop_toBottomOf="@id/tv222" />
​
 <androidx.constraintlayout.widget.Barrier
 android:id="@+id/barrier1"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 app:barrierDirection="end"
 app:constraint_referenced_ids="tv221 ,tv222" />
​
 <TextView
 android:id="@+id/tv223"
 style="@style/ConSampleText"
 android:layout_marginStart="10dp"
 android:text=".com"
 app:layout_constraintStart_toEndOf="@id/barrier1"
 app:layout_constraintTop_toTopOf="parent" />
​
 </androidx.constraintlayout.widget.ConstraintLayout>
調整約束偏差

對某個檢視的兩側新增約束條件(並且同一維度的檢視尺寸為“fixed”或者“wrap Content”)時,則該檢視在兩個約束條件之間居中且預設偏差為 50%。 可以通過設定屬性來調整偏差。 - app:layout_constraintVertical_bias - app:layout_constraintHorizontal_bias

例如

<androidx.constraintlayout.widget.ConstraintLayout
 android:id="@+id/c23"
 android:layout_width="match_parent"
 android:layout_height="140dp"
 android:layout_marginTop="10dp"
 android:background="#f3f3f3"
 app:layout_constraintEnd_toEndOf="parent"
 app:layout_constraintStart_toStartOf="parent"
 app:layout_constraintTop_toBottomOf="@id/c22">
​
 <TextView
 style="@style/ConSampleText"
 android:text="Rust"
 app:layout_constraintBottom_toBottomOf="parent"
 app:layout_constraintEnd_toEndOf="parent"
 app:layout_constraintStart_toStartOf="parent"
 app:layout_constraintTop_toTopOf="parent" />
​
 <TextView
 style="@style/ConSampleText"
 android:text="0.33,0.33"
 app:layout_constraintBottom_toBottomOf="parent"
 app:layout_constraintEnd_toEndOf="parent"
 app:layout_constraintHorizontal_bias="0.33"
 app:layout_constraintStart_toStartOf="parent"
 app:layout_constraintTop_toTopOf="parent"
 app:layout_constraintVertical_bias="0.33" />
​
 <TextView
 style="@style/ConSampleText"
 android:text="0.8,0.8"
 app:layout_constraintBottom_toBottomOf="parent"
 app:layout_constraintEnd_toEndOf="parent"
 app:layout_constraintHorizontal_bias="0.8"
 app:layout_constraintStart_toStartOf="parent"
 app:layout_constraintTop_toTopOf="parent"
 app:layout_constraintVertical_bias="0.8" />
​
 </androidx.constraintlayout.widget.ConstraintLayout>
調整檢視尺寸

這裡調整的是子 view 的尺寸。

Match Constraints 檢視會盡可能擴充套件,以滿足每側的約束條件(在考慮檢視的外邊距之後)。 不過,可以使用以下屬性和值修改該行為(這些屬性僅在您將檢視寬度設定為“match constraints”時才會生效):

layout_constraintWidth_default - spread:儘可能擴充套件檢視以滿足每側的約束條件。這是預設行為。
wrap:僅在需要時擴充套件檢視以適應其內容,但如有約束條件限制,檢視仍然可以小於其內容。因此,它與使用 Wrap Content(上面)之間的區別在於,將寬度設為 Wrap Content 會強行使寬度始終與內容寬度完全匹配;而使用 layout_constraintWidth_default 設定為 wrap 的Match Constraints 時,檢視可以小於內容寬度。

  • layout_constraintWidth_min 該檢視的最小寬度採用 dp 維度。
  • layout_constraintWidth_max 該檢視的最大寬度採用 dp 維度。

layout 中設定 android:layout_width="0dp"android:layout_height="0dp"。 確定好周圍的參照線。

<androidx.constraintlayout.widget.ConstraintLayout
 android:id="@+id/c24"
 android:layout_width="match_parent"
 android:layout_height="200dp"
 android:layout_marginTop="20dp"
 android:background="#009C8D"
 app:layout_constraintTop_toBottomOf="@id/c23">
​
 <androidx.constraintlayout.widget.Guideline
 android:id="@+id/v50"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:orientation="vertical"
 app:layout_constraintGuide_percent="0.5" />
​
 <androidx.constraintlayout.widget.Guideline
 android:id="@+id/h50"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:orientation="horizontal"
 app:layout_constraintGuide_percent="0.5" />
​
 <TextView
 style="@style/ConSampleText"
 android:layout_width="0dp"
 android:layout_height="0dp"
 android:layout_margin="30dp"
 android:gravity="center"
 android:text="R"
 app:layout_constraintBottom_toTopOf="@id/h50"
 app:layout_constraintEnd_toStartOf="@id/v50"
 app:layout_constraintStart_toStartOf="parent"
 app:layout_constraintTop_toTopOf="parent" />
​
 <TextView
 style="@style/ConSampleText"
 android:layout_width="0dp"
 android:layout_height="0dp"
 android:layout_margin="30dp"
 android:gravity="center"
 android:text="U"
 app:layout_constraintBottom_toTopOf="@id/h50"
 app:layout_constraintEnd_toEndOf="parent"
 app:layout_constraintStart_toEndOf="@id/v50"
 app:layout_constraintTop_toTopOf="parent" />
​
 <TextView
 style="@style/ConSampleText"
 android:layout_width="0dp"
 android:layout_height="0dp"
 android:layout_margin="30dp"
 android:gravity="center"
 android:text="S"
 app:layout_constraintBottom_toBottomOf="parent"
 app:layout_constraintEnd_toStartOf="@id/v50"
 app:layout_constraintStart_toStartOf="parent"
 app:layout_constraintTop_toBottomOf="@id/h50" />
​
 <TextView
 style="@style/ConSampleText"
 android:layout_width="0dp"
 android:layout_height="0dp"
 android:layout_margin="30dp"
 android:gravity="center"
 android:text="T"
 app:layout_constraintBottom_toBottomOf="parent"
 app:layout_constraintEnd_toEndOf="parent"
 app:layout_constraintStart_toEndOf="@id/v50"
 app:layout_constraintTop_toBottomOf="@id/h50" />
​
 </androidx.constraintlayout.widget.ConstraintLayout>

將尺寸設定為比例

比例為寬比高 width:height。如果寬高其中一個設定了大於0的具體值或wrap_content,可以其為標準來調整另一個尺寸引數。

示例

設定layout_width="40dp"android:layout_height="0dp",比例為3:2。 以寬40dp為基準,按比例調整高度。

<androidx.constraintlayout.widget.ConstraintLayout
 android:layout_width="@dimen/con_card_size"
 android:layout_height="@dimen/con_card_size"
 android:background="#f0f0f0">
​
 <TextView
 android:layout_width="40dp"
 android:layout_height="0dp"
 android:layout_marginTop="16dp"
 android:layout_marginBottom="16dp"
 android:background="#2196F3"
 android:gravity="center"
 android:text="3:2"
 android:textColor="#ffffff"
 app:layout_constraintBottom_toBottomOf="parent"
 app:layout_constraintDimensionRatio="3:2"
 app:layout_constraintEnd_toEndOf="parent"
 app:layout_constraintStart_toStartOf="parent"
 app:layout_constraintTop_toTopOf="parent" />
​
</androidx.constraintlayout.widget.ConstraintLayout>

Android零基礎入門教程視訊參考