文章目錄
- 一、前言
- 二、ConstraintLayout 的使用
- 2.1 引入依賴
- 2.2 在佈局中使用
- 2.3 ConstraintLayout 的約束詳解
- 2.3.1 相對位置約束
- 2.3.2 相對間距
- 2.3.3 關聯控件隱藏(View.GONE)時的間距
- 2.3.4 居中對齊
- 2.3.5 偏斜對齊
- 2.3.6 圓圈佈局
- 2.3.7 當依賴的控件隱藏(View.GONE)之後
- 2.3.8 像素約束
- 2.3.8.1 ConstraintLayout 裏的控件尺寸
- 2.3.8.2 ConstraintLayout 裏的控件最大、最小尺寸
- 2.3.8.3 WRAP_CONTENTE 的強制約束(1.1版本庫開始纔有效)
- 2.3.8.4 MATCH_CONSTRAINT 尺寸的妙用(1.1版本開始)
- 2.3.9 鏈控制
- 2.3.10 虛擬輔助對象
- 2.3.10.1 引導線約束
- 2.3.10.2 屏障約束
- 三、編後語
一、前言
大家都知道,在Android中是通過佈局來定義應用中的界面結構,隨着版本的更新迭代,有些佈局類型因爲適用性退出了歷史的舞臺,例如:AbsoluteLayout。也增了一些佈局類型,例如本文提到的 ConstraintLayout (ConstraintLayout 是 Android Jetpack 的一部分)。
在 Android 開發過程中,針對複雜的佈局,以往的實現方式只能通過多種類型的佈局疊加組合實現,但是這樣存在一個問題,就是佈局的嵌套層次過多,會影響UI的繪製性能,降低應用的品質。 ConstraintLayout 可以在無嵌套視圖組的前提下,實現扁平視圖層次結構,創建複雜的大型佈局。它與 RelativeLayout 相似,內部所有的視圖均根據同級視圖與父佈局之間的關係進行佈局,但其靈活性要遠高於 RelativeLayout。
二、ConstraintLayout 的使用
2.1 引入依賴
ConstraintLayout 是 Android Jetpack 的一部分,需要額外引入依賴包才能使用,在項目程序模塊下的 build.gradle
文加下增加依賴。
// support包引入,如果項目使用其他support包,使用這個
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
// androidx包引入,如果項目使用androidx時使用,跟support包引入只能選其一,否則會衝突
implementation 'androidx.constraintlayout:constraintlayout:2.0.0-beta7'
注意事項:確保您的
maven.google.com
代碼庫已在模塊級 build.gradle 文件中聲明(較新版的AndroidStudio新建項目都會自動加入,如果是很老的舊項目,請檢查代碼庫配置)。
2.2 在佈局中使用
因爲 ConstraintLayout 是 Android Jetpack 的一部分,所以引用以及屬性使用,都跟系統控件有些不一樣
<?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"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent" />
</android.support.constraint.ConstraintLayout>
說明:
- 非系統控件,在佈局文件中使用需要使用類名全名(這跟自定義控件一樣);
- 非系統控件,自定義的屬性需要添加
xmlns:app="http://schemas.android.com/apk/res-auto"
引入屬性(其中app
是可以任意命名,但是不能用android
,因爲這個已被系統使用。)
2.3 ConstraintLayout 的約束詳解
ConstraintLayout 佈局主要通過相互約束來控制佈局的,下面將會詳細介紹下這些約束。
2.3.1 相對位置約束
相對位置約束是指一個控件跟父級容器或者其他同級控件之間的相對位置,相對位置有以下幾個要素(如下圖所示):
- 水平方向:
left
(左邊)、right
(右邊)、start
(起始邊)、end
(結束邊) - 垂直方向:
top
(上邊)、bottom
(下邊)、text baseline
(文字基線,這個只對有文本的控件有效)
說明:其實
left
與start
、right
與end
是相同的。
控制相對位置約束的屬性有以下這些:
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
:控件結束邊與目標控件結束邊的約束條件
示例
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">
<Button
android:id="@+id/btn1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button1"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
<Button
android:id="@+id/btn2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button2"
app:layout_constraintLeft_toRightOf="@+id/btn1"
app:layout_constraintTop_toBottomOf="@+id/btn1"/>
</androidx.constraintlayout.widget.ConstraintLayout>
效果:
注意事項:相對位置約束的屬性在使用過程中,部分屬性之間是衝突的,在使用過程中要特別注意。例如:
layout_constraintLeft_toLeftOf
和layout_constraintLeft_toRightOf
,一個控件的左邊不可能同時跟目標控件的左邊和右邊存在約束。
2.3.2 相對間距
ConstraintLayout
的間距爲什麼說是相對的呢?因爲設置的間距都是相對約束的目標控件的間距,如下圖所示:Button2 左邊對齊 Button1 的右邊,所以,當 Button2 設置左間距 30dp 時,是相對 Button1 的右邊。
注意:如果控件居中顯示,設置了間距之後,居中的位置也會相對變化(會線除去間距的位置之後再居中),關於在
ConstraintLayout
中居中的相關內容參考: 居中對齊
設置間距屬性如下:
android:layout_marginStart
android:layout_marginEnd
android:layout_marginLeft
android:layout_marginTop
android:layout_marginRight
android:layout_marginBottom
說明:設置間距的屬性使用的是框架自帶屬性,不是 ConstraintLayout 自定義屬性,所以以
android
爲命名空間。
2.3.3 關聯控件隱藏(View.GONE)時的間距
關聯控件隱藏(View.GONE)時的間距,跟相對間距類似,不同的是,他是在關聯控件隱藏(View.GONE)之後纔會生效。
示例:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">
<Button
android:id="@+id/btn1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button1"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
<Button
android:id="@+id/btn2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button2"
app:layout_constraintLeft_toRightOf="@+id/btn1"
app:layout_constraintTop_toBottomOf="@+id/btn1"
android:layout_marginLeft="30dp"
android:visibility="visible"/>
<Button
android:id="@+id/btn3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button3"
app:layout_constraintRight_toLeftOf="@+id/btn2"
app:layout_constraintTop_toBottomOf="@+id/btn2"
android:layout_marginTop="30dp"
app:layout_goneMarginTop="100dp"/>
</androidx.constraintlayout.widget.ConstraintLayout>
效果:
以上示例中,當 Button2 隱藏(gone)之後,Button3的上間距由原來的30dp變爲了50dp,至於爲什麼Button3的位置會發生改變,這個參考:當依賴的控件隱藏(View.GONE)之後
2.3.4 居中對齊
在ConstraintLayout裏面的控件都是靠關聯約束進行控制的,那麼如何實現居中對齊呢?實現起來其實也很簡單,只需兩個方向同時設置關聯控件就可以實現在兩個關聯點之間居中。
- 水平居中:同時設置左、右兩邊的關聯約束
- 垂直居中: 同時設置上、下兩邊的關聯約束
示例:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">
<Button
android:id="@+id/btn1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button1"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
效果:
說明:如果控件設置了間距,那麼居中對齊的時候會除去設置的間距之後再居中,以上的例子中,雖然Button1的左邊是跟父容器的左邊關聯,但是如果設置了左間距爲100dp的話,那麼Button1水平方向是父容器左邊100dp處跟右邊居中。
2.3.5 偏斜對齊
偏斜對齊是當控件同時設置了兩邊的關聯之後,控件要往某一邊進行偏斜(靠近),偏斜值是一個 float
類型數字,取值 0 ~ 1.0 之間(其實 居中對齊 就是偏斜值爲 0.5 的特例)。偏斜分爲水平和垂直兩個方向。
layout_constraintHorizontal_bias
:水平偏斜layout_constraintVertical_bias
:垂直偏斜
示例:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">
<Button
android:id="@+id/btn1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button1"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHorizontal_bias="0.3"
app:layout_constraintVertical_bias="0.4"/>
</androidx.constraintlayout.widget.ConstraintLayout>
效果:
2.3.6 圓圈佈局
圓圈佈局,就是空間圍繞關聯控件,以指定的半徑、角度進行佈局。例如:你可以用圓圈佈局輕鬆實現一個組合控件圓形錶盤(而不是自定義控件)。
圓圈佈局主要有三個屬性:
layout_constraintCircle
:關聯的控件(也就是圓心所在的控件)layout_constraintCircleRadius
: 圓形半徑(控件中心點與所關聯控件中心點之間的距離)layout_constraintCircleAngle
: 角度(0~360度,正上方爲0度)
示例(圓形錶盤):
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">
<Button
android:id="@+id/btn1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button1"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintVertical_bias="0.5"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="12"
app:layout_constraintCircle="@+id/btn1"
app:layout_constraintCircleRadius="100dp"
app:layout_constraintCircleAngle="0"
android:textSize="16sp"
android:textColor="@android:color/black"
android:visibility="visible"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="1"
app:layout_constraintCircle="@+id/btn1"
app:layout_constraintCircleRadius="100dp"
app:layout_constraintCircleAngle="30"
android:textSize="16sp"
android:textColor="@android:color/black"
android:visibility="visible"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="2"
app:layout_constraintCircle="@+id/btn1"
app:layout_constraintCircleRadius="100dp"
app:layout_constraintCircleAngle="60"
android:textSize="16sp"
android:textColor="@android:color/black"
android:visibility="visible"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="3"
app:layout_constraintCircle="@+id/btn1"
app:layout_constraintCircleRadius="100dp"
app:layout_constraintCircleAngle="90"
android:textSize="16sp"
android:textColor="@android:color/black"
android:visibility="visible"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="4"
app:layout_constraintCircle="@+id/btn1"
app:layout_constraintCircleRadius="100dp"
app:layout_constraintCircleAngle="120"
android:textSize="16sp"
android:textColor="@android:color/black"
android:visibility="visible"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="5"
app:layout_constraintCircle="@+id/btn1"
app:layout_constraintCircleRadius="100dp"
app:layout_constraintCircleAngle="150"
android:textSize="16sp"
android:textColor="@android:color/black"
android:visibility="visible"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="6"
app:layout_constraintCircle="@+id/btn1"
app:layout_constraintCircleRadius="100dp"
app:layout_constraintCircleAngle="180"
android:textSize="16sp"
android:textColor="@android:color/black"
android:visibility="visible"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="7"
app:layout_constraintCircle="@+id/btn1"
app:layout_constraintCircleRadius="100dp"
app:layout_constraintCircleAngle="210"
android:textSize="16sp"
android:textColor="@android:color/black"
android:visibility="visible"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="8"
app:layout_constraintCircle="@+id/btn1"
app:layout_constraintCircleRadius="100dp"
app:layout_constraintCircleAngle="240"
android:textSize="16sp"
android:textColor="@android:color/black"
android:visibility="visible"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="9"
app:layout_constraintCircle="@+id/btn1"
app:layout_constraintCircleRadius="100dp"
app:layout_constraintCircleAngle="270"
android:textSize="16sp"
android:textColor="@android:color/black"
android:visibility="visible"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="10"
app:layout_constraintCircle="@+id/btn1"
app:layout_constraintCircleRadius="100dp"
app:layout_constraintCircleAngle="300"
android:textSize="16sp"
android:textColor="@android:color/black"
android:visibility="visible"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="11"
app:layout_constraintCircle="@+id/btn1"
app:layout_constraintCircleRadius="100dp"
app:layout_constraintCircleAngle="330"
android:textSize="16sp"
android:textColor="@android:color/black"
android:visibility="visible"/>
</androidx.constraintlayout.widget.ConstraintLayout>
效果:
2.3.7 當依賴的控件隱藏(View.GONE)之後
在 ConstraintLayout 中,對控件的隱藏(View.GONE)有着獨特的處理。通常,如果一個控件隱藏(View.GONE)之後,它不會在展示,並且不在屬於佈局的一部分。但是,在佈局的計算過程中,隱藏的控件仍舊是佈局中的一部分,但是它又有着重要的區別。
- 在整個佈局中,隱藏的控件尺寸會被當做0(基本上可以當做是一個點);
- 如果隱藏的控件關聯了其他控件,關聯關係依舊存在,但是所有的間距會變爲0;
- 如果隱藏的控件被其他控件關聯,關聯關係和間距都會不變,但是關聯改隱藏控件的的控件,顯示位置會發生變化。
講解:當Button1 隱藏時,在佈局計算時,隱藏的 Button1 相當於一個點,並且跟父容器的關聯關係不變,如果 Button1 設置了間距,也將會不起作用,對於關聯了 Button1 的 Button2,間距和關聯不會改變,但是由於 Button1 的計算屬性發生變化,Button2 的位置會發生相應的變化。
2.3.8 像素約束
2.3.8.1 ConstraintLayout 裏的控件尺寸
在 ConstraintLayout 中,控件的尺寸通過 android:layout_width
和 android:layout_height
兩個屬性設置。
- 固定數值
- 使用
WRAP_CONTENTE
,讓控件計算出自身的尺寸 - 使用 “0dp”(等同於使用
MATCH_CONSTRAINT
),鋪滿父容器
2.3.8.2 ConstraintLayout 裏的控件最大、最小尺寸
android:minWidth
:設置控件在佈局中的最小寬度android:minHeight
:設置控件在佈局中的最小高度android:maxWidth
:設置控件在佈局中的最大寬度android:maxHeight
:設置控件在佈局中的最大高度
說明:設置控件在佈局中的最大、最小尺寸,只有在尺寸設置爲自適應(WRAP_CONTENT)時有效。
2.3.8.3 WRAP_CONTENTE 的強制約束(1.1版本庫開始纔有效)
在 ConstraintLayout 中,如果控件的尺寸設置爲 WRAP_CONTENT
,他將被視爲“文字”尺寸,如果控件內部的文字內容很長,將控件撐開的時候,就會出現控件設置的間距出現異位甚至被擠出到父容器範圍外,這時,你需要使用強制執行約束來限制控件的最終尺寸,可以使用以下屬性設置強制執行約束:
app:layout_constrainedWidth=”true|false”
:水平方向強制執行約束app:layout_constrainedHeight=”true|false”
:垂直方向強制執行約束
示例:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">
<Button
android:id="@+id/btn1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button1222222222222222222222222222222222222222222222222222222222"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintVertical_bias="0.5"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
android:layout_marginLeft="50dp"/>
</android.support.constraint.ConstraintLayout>
效果:
2.3.8.4 MATCH_CONSTRAINT 尺寸的妙用(1.1版本開始)
在設置尺寸時,對於 MATCH_PARENT
和 WRAP_CONTENT
我們特別熟悉,但是 MATCH_CONSTRAINT
是什麼鬼?在 XML 佈局文件中,也並不能使用這個類型。我們查看 ConstraintLayout.LayoutParams
類的時候就可以看到這個字段 ConstraintLayout.LayoutParams.MATCH_CONSTRAINT = 0
,在 XML 佈局文件中,使用這個類型的尺寸只需要設置爲 0dp
,這個是不是很熟悉呢?在 LinearLayout
中,使用 android:layout_weight
屬性的時候是不是也這麼幹過。
2.3.8.4.1 如何讓控件鋪滿父容器
當筆者第一次接觸 ConstraintLayout
的時候,我有一個疑問,就是如何讓一個在其中的控件不慢整個容器呢?顯然通過四邊添加跟父容器的約束是不可行的(這種做法只是居中),知道發現了 MATCH_CONSTRAINT
這個尺寸類型,才豁然開朗,對於 MATCH_CONSTRAINT
而言,它的默認值就是鋪滿父容器。
示例:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">
<Button
android:id="@+id/btn1"
android:layout_width="0dp"
android:layout_height="0dp"
android:text="Button122"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginLeft="50dp"/>
</androidx.constraintlayout.widget.ConstraintLayout>
效果:
注意:如果你使用了邊距(margin),鋪滿全屏的時候會保持着邊距。
2.3.8.4.2 MATCH_CONSTRAINT 約束模式切換
前面說到,對於 MATCH_CONSTRAINT
而言,它默認值是鋪滿父容器的,其實,ConstraintLayout
還提供了非常靈活的約束模式切換,通過切換不同的模式和屬性組合,可以滿足不同的使用場景要求。 約束模式的切換使用以下屬性:
layout_constraintWidth_default
:橫向約束模式layout_constraintHeight_default
:縱向約束模式
約束模式的取值有:
取值 | 說明 |
---|---|
spread |
鋪開全屏(默認) |
wrap |
根據內容變化控件大小 |
percent |
按比例控制控件大小(默認1,鋪滿父容器) |
2.3.8.4.3 約束模式與不同屬性組合的神奇效果
MATCH_CONSTRAINT 約束可以使用的屬性除了前面介紹的之外,還有以下屬性:
-
最大與最小
layout_constraintWidth_min
:橫向最小尺寸layout_constraintHeight_min
:縱向最小尺寸layout_constraintWidth_max
:橫向最大尺寸layout_constraintHeight_max
:縱向最大尺寸
-
父容器百分比
layout_constraintWidth_percent
:橫向父容器百分佔比(取值0~1)layout_constraintHeight_percent
:縱向父容器百分佔比(取值0~1)
-
橫縱比
layout_constraintDimensionRatio
:橫縱尺寸比例(如 1:1 表示橫向和縱向尺寸比例爲1:1,即正方形)
-
約束模式與屬性的搭配
約束類型 | 有效的屬性 | 效果描述 | 備註 |
---|---|---|---|
spread |
layout_constraintWidth_max layout_constraintHeight_max layout_constraintDimensionRatio |
控制控件橫向和縱向的大小 | - |
wrap |
layout_constraintWidth_min layout_constraintHeight_min layout_constraintWidth_max layout_constraintHeight_max layout_constraintDimensionRatio |
分別控制橫向和縱向的最大與最小 | 如果橫向和縱向都是 wrap ,使用 layout_constraintDimensionRatio 屬性時,必須至少指定 layout_constraintWidth_max 和 layout_constraintHeight_max 中的一個 |
percent |
layout_constraintWidth_percent layout_constraintHeight_percent layout_constraintWidth_min layout_constraintHeight_min layout_constraintWidth_max layout_constraintHeight_max |
這個百分比的類型,幾乎所有屬性都可用,最大最小值只會在百分比超過靈界點之後生效,例如:如果百分佔比的尺寸小於最小值,則取最小值,如果百分佔比的尺寸大於最大值,則取最大值,但是需要注意的是,如果使用這個類型的約束,最大和最小隻能使用一個,否則就會出現意想不到的問題,如果不是特殊需要,在使用百分比的時候,儘量不要配合最大和最小值。 | - |
示例:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">
<Button
android:id="@+id/btn1"
android:layout_width="0dp"
android:layout_height="0dp"
android:text="Button1222222222222222222222222222222222222222222222222"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintWidth_default="wrap"
app:layout_constraintWidth_min="200dp"
app:layout_constraintWidth_max="300dp"
app:layout_constraintHeight_default="percent"
app:layout_constraintHeight_percent="0.5"
app:layout_constraintHeight_max="200dp"
android:layout_marginLeft="50dp"/>
</androidx.constraintlayout.widget.ConstraintLayout>
效果:
注意事項:各個屬性的使用千變萬化,對於橫向和縱向使用不同的約束模式也會有不一樣的效果。
2.3.9 鏈控制
鏈控制線性約束是指在單個方向上(水平或者垂直)實現類似組的行爲,另一個方向可以獨立約束。鏈控制線性約束,實際上就是將一組控件放在一起,相互依賴形成一條鏈。
示例:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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/btn1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="@+id/btn2"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:text="Button1" />
<Button
android:id="@+id/btn2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button2"
app:layout_constraintStart_toEndOf="@+id/btn1"
app:layout_constraintEnd_toStartOf="@+id/btn3"
app:layout_constraintRight_toLeftOf="@+id/btn3"
app:layout_constraintTop_toTopOf="@+id/btn1"
android:visibility="visible"/>
<Button
android:id="@+id/btn3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button3"
app:layout_constraintStart_toEndOf="@+id/btn2"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="@+id/btn2"/>
</androidx.constraintlayout.widget.ConstraintLayout>
效果:
2.3.9.1 鏈頭
鏈控制線性約束有一個鏈頭,它是整個鏈的第一個元素(水平是最左一個元素、垂直是最上上的一個元素),在鏈頭上設置屬性可控制鏈條的樣式。
2.3.9.2 鏈的樣式
通過在鏈頭上設置鏈樣式屬性,可以改變鏈的樣式。
layout_constraintHorizontal_chainStyle
:水平方向鏈的樣式(默認爲CHAIN_SPREAD)layout_constraintVertical_chainStyle
:垂直方向鏈的樣式(默認爲CHAIN_SPREAD)
樣式取值 | 說明 | 備註 |
---|---|---|
CHAIN_SPREAD |
元素將散佈,每個元素佔有效空間的一個比重並居中 | 默認樣式,XML中對應 spread ,間距會影響元素的位置 |
CHAIN_SPREAD _INSIDE |
內部元素散佈,前後兩個元素緊靠有效空間的邊沿 | XML中對應 spread_inside ,間距會影響元素的位置 |
CHAIN_PACKED |
將鏈中的元素打包在一起居中對齊 | XML中對應 packed ,間距和偏斜對齊會影響元素的位置 |
注意事項:鏈會在父容器的有效空間中進行佈局,如果設置了邊距,將會先去掉間距,間距屬性在每個元素都可以生效。對於
CHAIN_PACKED
樣式,偏斜對齊起作用,雖然是在鏈頭中配置,但是生效的效果確實整個打包起來的鏈整體。
2.3.9.3 帶權重的鏈
鏈的默認行爲是將元素平均分佈在可用空間中。如果一個或多個元素使用MATCH_CONSTRAINT
(0dp),則這些元素將使用可用的空白空間(在它們之間平均分配)。元素的權重可以通過以下屬性進行設置:
-
layout_constraintHorizontal_weight
:水平方向權重 -
layout_constraintVertical_weight
: 垂直方向權重 -
示例
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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/btn1"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="@+id/btn2"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHorizontal_chainStyle="spread"
app:layout_constraintHorizontal_weight="2"
android:text="Button1" />
<Button
android:id="@+id/btn2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="Button2"
app:layout_constraintStart_toEndOf="@+id/btn1"
app:layout_constraintEnd_toStartOf="@+id/btn3"
app:layout_constraintRight_toLeftOf="@+id/btn3"
app:layout_constraintTop_toTopOf="@+id/btn1"
app:layout_constraintHorizontal_weight="3"
android:visibility="visible"/>
<Button
android:id="@+id/btn3"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="Button3"
app:layout_constraintStart_toEndOf="@+id/btn2"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintHorizontal_weight="3"
app:layout_constraintTop_toTopOf="@+id/btn2"/>
</androidx.constraintlayout.widget.ConstraintLayout>
- 效果
注意事項:
1. 當且僅當元素的尺寸使用MATCH_CONSTRAINT
(0dp)時,權重屬性才生效;
2. 爲元素添加權重,對鏈樣式沒有要求,因爲鏈樣式只是在元素大小適應內容時的效果,對於權重,是直接鋪滿可用空間。
2.3.10 虛擬輔助對象
所謂的虛擬輔助對象,就是一種虛擬存在,用來輔助佈局約束的,但是並不會真正在視圖中進行繪製。
2.3.10.1 引導線約束
引導線(Guideline)就是一種非常廣泛的虛擬輔助對象,引導線不是一個屬性,是一個虛擬輔助對象,添加引導線跟添加控件一樣。引導線分爲水平和垂直兩個方向,使用 android:orietation
屬性控制方向。除了控制方向之外,引導線還有控制位置的的屬性:
-
layout_constraintGuide_begin
:距離父容器左側的距離 -
layout_constraintGuide_end
:距離父容器右側的距離 -
layout_constraintGuide_percent
:在父容器(左側)的百分比例(取值0.0~1.0) -
示例
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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">
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.3" />
<Button
android:id="@+id/btn4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="30dp"
android:text="Button4"
app:layout_constraintLeft_toRightOf=" @+id/guideline"/>
</androidx.constraintlayout.widget.ConstraintLayout>
- 效果
2.3.10.2 屏障約束
與引導線類似,屏障是一條隱藏的線,可以用它來約束視圖。跟引導線不同的是,屏障不會定義自己的位置;相反,屏障的位置會隨着其中所含視圖的位置而移動。如果您希望將視圖限制到一組視圖而不是某個特定視圖,這就非常有用。屏障約束主要通過 Barrier 類及其屬性進行控制,Barrie
類的屬性有以下幾個:
-
barrierDirection
:屏障約束的方向,這個是指約束的內容在屏障的哪個位置 -
constraint_referenced_ids
:約束限制的控件id數組,多個用半角逗號隔開 -
示例代碼:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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">
<androidx.constraintlayout.widget.Barrier
android:id="@+id/barrier"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:barrierAllowsGoneWidgets="false"
app:barrierDirection="right"
app:constraint_referenced_ids="btn5,btn6" />
<Button
android:id="@+id/btn5"
android:layout_width="250dp"
android:layout_height="wrap_content"
android:text="Button5"
app:layout_constraintLeft_toLeftOf="parent"/>
<Button
android:id="@+id/btn6"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:text="Button6"
app:layout_constrainedWidth="true"
app:layout_constraintTop_toBottomOf="@+id/btn5" />
<Button
android:id="@+id/btn7"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button777777777777777777777777777777777777777777777777777777777777777777777777777777777"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintLeft_toRightOf="@+id/barrier"
app:layout_constrainedWidth="true"/>
</androidx.constraintlayout.widget.ConstraintLayout>
- 效果:
以上的例子中,定義了一個屏障,屏障約束的方向是
right
,也就是屏障右邊的內容根據屏障內部的內容變動而動態變化。屏障內部的控件組包含了 button5 和 button6,屏障的位置會根據屏障內部的控件動態變化,從而限制 button7 的佈局變化。
三、編後語
ConstraintLayout 是一個非常強大的佈局,扁平化的佈局,提高UI的繪製效率,提高性能方面做得非常好。